1.7.32 ba_data update

This commit is contained in:
Ayush Saini 2023-12-21 15:55:50 +05:30
parent bf2f252ee5
commit 15393d5461
144 changed files with 4296 additions and 2411 deletions

View file

@ -12,7 +12,7 @@
"Filipino": "Tagalog ",
"French": "Français",
"German": "Deutsch",
"Gibberish": "Gibberish",
"Gibberish": "Abuktarika",
"Greek": "Ελληνικά",
"Hindi": "हिंदी",
"Hungarian": "Magyar",
@ -42,13 +42,18 @@
"!nobal",
"!ParkuristTurist!",
"\"9۝ÅЇρѺ۝ƬǀGΞЯ",
"\"Unknown\"",
"/in/dev/",
"1.4.139",
"11",
"123",
"123123123",
"1Platinumpatty",
"1SpaZ",
"228варенье",
"233",
"26885",
"3alTemp",
"43210",
"5PH3X",
"99",
@ -100,6 +105,7 @@
"Carlos Mario Agamez",
"ageng",
"Dimitris Aggelou",
"AGØTI",
"ariyan ahir",
"AHMAD",
"Aufan Ahmad",
@ -113,6 +119,7 @@
"Aki",
"Abdullah Akkan",
"Berk Akkaya",
"AkVoN",
"AKYG",
"mohammed al-abri",
"Ali Al-Gattan",
@ -128,12 +135,14 @@
"Alex",
"Alexander",
"Gros Alexandre",
"AlexBx",
"Alexey",
"Alexgmihai",
"Alexis",
"Alexistb2904",
"Alexyze",
"Algene123456",
"Alguien_201",
"ALI",
"Mohamed ali",
"Shadiq Ali",
@ -144,6 +153,7 @@
"Allinol",
"ahmed alomari",
"Alonso",
"Alp",
"Alper",
"Alpha",
"AlphaT",
@ -164,6 +174,7 @@
"amir234",
"amir80sas",
"AmirMahdi.D :P",
"amirsaman050",
"Amirul",
"Ange Kevin Amlaman",
"AMOGUSS85",
@ -214,6 +225,7 @@
"arjanex",
"Arroz",
"ARSHAD",
"Arshia",
"ArshiyDLn",
"Artem",
"Valentino Artizzu",
@ -244,6 +256,7 @@
"Azlan",
"Azoz",
"Burak Karadeniz (Myth B)",
"Leonan B.",
"Myth B.",
"B4likeBefore",
"Praveen Babu",
@ -280,6 +293,7 @@
"Wojtek Bałut",
"Hi bbbbbbbbb",
"Eduardo Beascochea",
"Keyhan Behzadi",
"Eduan Bekker",
"бравлер Андрей Belarus",
"ben",
@ -302,6 +316,7 @@
"Anton Bang Berner",
"Felix Bernhard",
"Beroudzin",
"Abhishek Bhardwaj",
"Davide Bigotto",
"bilibili@Medic药",
"Bima",
@ -348,6 +363,8 @@
"bsam",
"Bsamhero",
"BSODPK",
"Bub",
"Bubas",
"Marvin Bublitz",
"BudaCcm",
"Vincent R. Buenaventura",
@ -382,6 +399,7 @@
"Arthur Cazes",
"CerdoGordo",
"Ceren",
"cflagos",
"chang",
"Charlie",
"kalpesh chauhan",
@ -445,6 +463,7 @@
"DarshaN",
"Shibin das",
"Dasto",
"Davi",
"David",
"Davide",
"DavidPlayzLol",
@ -454,16 +473,20 @@
"Die or Dead",
"Привет от детей DeadLine",
"deepjith",
"Defiant",
"dekarl",
"deliciouspudding43",
"deliplayer",
"delshe",
"Denis",
"Dennis",
"Dennys",
"Alex Derbenew",
"Ingegner Devecchi",
"Dr : developer",
"df",
"Santanu Dhar",
"DHRUVIL",
"Guilherme Dias",
"Diase7en",
"ferbie Dicen",
@ -485,11 +508,14 @@
"Dmitriy",
"Savchenko Dmitriy",
"Count Su Doku",
"Giuseppe Valerio Dominici",
"DominikSikora!",
"Kai Dominique",
"Gerardo Doro",
"DottorMorte",
"Doubleknig",
"Dragomir",
"Dreaming",
"Drellsan",
"DrGhast",
"Dron009",
@ -503,6 +529,7 @@
"Emir İslam Dündar",
"E.R.A.L",
"Ebutahapro07tr",
"Eder",
"Edson",
"Glen Edwards",
"Amr Wassiem Eessa",
@ -533,11 +560,12 @@
"emm",
"EnderDust123",
"EnderKay",
"Endless_jk",
"EnglandFirst",
"Enrico",
"enzo",
"Era",
"Era0S (Spazton)",
"Era0S",
"Erick",
"Erkam",
"Jonas Ernst",
@ -573,6 +601,7 @@
"Shaikh Fazal",
"Fea",
"FearLessCuBer",
"Feder-28",
"Feder28",
"Federico",
"Fedrigo",
@ -591,6 +620,7 @@
"Aldereus Fire",
"Robert Fischer",
"Kai Fleischmann",
"FLOKI",
"Iancu Florin",
"FluffyPal",
"FLᎧRᏋᏁTIᏁᎧ",
@ -602,6 +632,7 @@
"Andrey Fridholm",
"FriskTheHuman303",
"Froshlee14",
"FrostyXD",
"FuckIndoDick",
"Lukas Funk",
"Gustavo FunnyGuard28",
@ -615,20 +646,24 @@
"João Gabriel",
"Gabriele",
"Nihar Gajare",
"GalaxyM4",
"GalaxyNinja2003",
"AP - Pro Gamer",
"Proff Gamer",
"Eduardo Gamer05",
"Gamer2809",
"Taufiq Gamera",
"Altangerel Ganbaatar",
"Quentin Gangler",
"RUSLAN ABDUL GANI",
"Garou",
"Gaspard",
"krish gator",
"gene.mTs",
"GeoMatHeo",
"Gerry",
"GG (9.2)",
"ggMustaGD0",
"Mohammad gh",
"Onkar Ghagarum",
"GHAIS",
@ -642,6 +677,7 @@
"Aidan Gil",
"Noe Marley Ginting",
"Giovalli99",
"Devecchi Giovanni",
"DEVEGGHI GIOVANNI",
"Giovanny",
"Dc superhero girl",
@ -671,6 +707,8 @@
"Tódor Gábor",
"Tymoteusz Górski",
"Thomas Günther",
"Hamza Emin GÜRLER",
"Paşa Güven",
"H.J.N",
"Haasaani",
"Hack",
@ -725,6 +763,7 @@
"Minh Hoang",
"Robin Hofmann",
"hola",
"holasoycuyo",
"Sebasian Varela Holguin",
"Holystone",
"Jeremy Horbul",
@ -736,6 +775,8 @@
"Hussain",
"Umair Hussain",
"Hussam",
"Huy",
"HYr",
"Adrian Höfer",
"Davide Iaccarino",
"iBearzGaming",
@ -749,6 +790,7 @@
"IL_SERGIO",
"!YamGila (Syed Ilham)",
"Iliya_bomB",
"Iliyafeili",
"illonis",
"Syed Ilham Ilman",
"Ily77788",
@ -829,8 +871,10 @@
"Rudransh Joshi (FireHead)",
"joshuapiper",
"Jossiney",
"Juangame65",
"juanramirez",
"Jules",
"Junior4pro",
"juse",
"Justine",
"JYLE",
@ -883,6 +927,7 @@
"$RICO$ KhevenMito",
"Khwezi",
"kibro",
"Kicken07",
"Joop Kiefte",
"killer",
"killer313",
@ -899,6 +944,7 @@
"komasio",
"komasio71",
"KomodoRec",
"koolych (Николай)",
"Niko Koren",
"Nikolay Korolyov",
"Kostas",
@ -914,6 +960,7 @@
"Krunal",
"kueue",
"Alok Kumar",
"Parth Kumar",
"sarath kumar",
"Aapeli Kumpulainen",
"Aldhiza Kurniawan",
@ -925,7 +972,9 @@
"Kyle",
"Jan Kölling",
"L_JK",
"Laaziz",
"Labrador",
"labrosggv",
"John Patrick Lachica",
"laikrai",
"m a lakum",
@ -939,8 +988,10 @@
"Lazydog",
"Elia Lazzari",
"이지민 (Ji-Min Lee)",
"legended",
"Mick Lemmens",
"Leo",
"Mr. LeoLeo",
"Lester",
"Szajkajkó Levente",
"Szajkajó Levente",
@ -951,6 +1002,7 @@
"Juan Liao",
"LickyBeeYT",
"Nicola Ligas",
"Alef costa lima",
"Limak09",
"LimonAga",
"lin",
@ -958,11 +1010,14 @@
"Kyle Lin",
"Linus",
"Linux44313",
"LioLioFlo",
"Lionel",
"Lippu",
"Lisavidxxxxxxx5",
"LiteBalt",
"LittleNyanCat",
"Juunhao Liu",
"Lixar",
"Lizz",
"Lizzetc",
"Lkham",
@ -992,6 +1047,7 @@
"Luis(GalaxtM4)",
"luislinares",
"luispro25",
"Luiz",
"Luka",
"Luke",
"Luke994",
@ -999,20 +1055,24 @@
"Hermanni Luosujärvi",
"Lurã",
"Luthy",
"Luytaris",
"Geogre Lyu",
"Be aware that m",
"Matias M.",
"M.R.T",
"M5TF4",
"Mac 143338",
"MaceracıMS",
"Samuel Maciel",
"Djawad madi",
"MadNightr",
"Mads Beier Madsen",
"Mahan",
"Ondřej Mahdalík",
"mahdi",
"mahdimahabadi",
"Mahmoud",
"Mahziyar",
"maicol",
"Majestozão",
"Makar",
@ -1020,6 +1080,7 @@
"Malaysian",
"EMILIO MALQUIN",
"MAMAD",
"Wagdy mamdouh",
"Mani",
"Manimutharu",
"Ahmed Mansy",
@ -1032,6 +1093,7 @@
"Marcolino",
"Filip Marek",
"Marcin Marek",
"Margarrom",
"Mariel",
"Marin",
"mariuxoGaming",
@ -1072,6 +1134,7 @@
"Kevin Mejía",
"Mell",
"MereCrack",
"Merengue",
"Mert",
"Meryu07",
"Meysam",
@ -1090,6 +1153,7 @@
"Mina",
"minh123456789thcsvk",
"MinhAn19203",
"Michael J. Soto Miranda",
"Azfar Ahmed Mirza",
"misael",
"Deepak Mishra",
@ -1109,6 +1173,7 @@
"Mohammad11dembele",
"MOHAMMADERFAN",
"Mohammadhosain",
"Mohammadpl",
"Mohammed",
"MOHAMMEDTALAL1ST",
"1n Mohhaamad",
@ -1143,6 +1208,7 @@
"Mwss",
"MYSENIOR",
"mythbrk00@gmail.com",
"محمدحسین MZZ",
"Sajti Márk",
"Samuel Mörling",
"Luca Müller",
@ -1198,11 +1264,15 @@
"NofaseCZ",
"Max Noisa",
"Noisb",
"NoNameC3698241",
"None",
"NOOBPEDAR",
"Noobslaya101",
"noorjandle1",
"Petter Nordlander",
"Nose",
"NotBrojasAgain",
"NotDiegoGD",
"Ntinakos555",
"NullWizard",
"Dhimas Wildan Nz",
@ -1217,6 +1287,7 @@
"omgxd5",
"On3GaMs",
"No one",
"oneman",
"Adam Oros",
"Andrés Ortega",
"Zangar Orynbetov",
@ -1251,6 +1322,7 @@
"PC432736",
"PC607666",
"PC912334",
"PC979802",
"pebikristia",
"Pedro",
"Jiren/Juan Pedro",
@ -1282,6 +1354,7 @@
"Elian Pj",
"Broi PL",
"Ziomek PL",
"George Play's",
"Anestis Plithos",
"Pluisbaard",
"Jaideep Kumar PM",
@ -1334,6 +1407,7 @@
"Rahul Raman",
"Vicente Ramirez",
"ramon",
"Ramzy",
"Randlator",
"Random_artz__",
"Rares",
@ -1375,6 +1449,7 @@
"Ridzuan",
"Samuel Rieger",
"RieJoemar",
"Rings3467",
"Jeroen Rinzema",
"RioAdir",
"Max Rios",
@ -1422,6 +1497,7 @@
"Matteo Salvini",
"Salvo04",
"Samen",
"Samsep10l",
"San",
"SaNt0RiNiKits577YT",
"Guilherme Santana",
@ -1440,6 +1516,8 @@
"Hendrik Schur",
"SEBASTIAN2059",
"Semen",
"semethers",
"JIN SEOWOO",
"Mihai Serbanica",
"Daniel Balam Cabrera Serrano",
"Yefta Aditya Setiawan",
@ -1466,6 +1544,7 @@
"Simotoring",
"Pawan Singh sisodiya",
"Skick",
"SkillPro",
"sks",
"Max Sky",
"SlayTaniK",
@ -1491,6 +1570,7 @@
"speddy16",
"Spielfreake (Garke)",
"Spielfream",
"Spooc",
"Spy",
"SqdDoom",
"sss",
@ -1500,6 +1580,7 @@
"Bartosz Staniszewski",
"Stare",
"StarFighter",
"Artem Stasyuk",
"Rz Stazzy",
"Stealives",
"Steffo",
@ -1512,6 +1593,7 @@
"STPayoube",
"Stratex",
"SYED EPIC STUDIOS",
"SUBC1PYZH",
"sun.4810",
"Samet Sunal",
"sundar",
@ -1588,6 +1670,7 @@
"Tory",
"TozeLeal",
"Trung Hieu Le Tran",
"Small Translation",
"Translator",
"TrialTemp",
"Trivago",
@ -1599,6 +1682,7 @@
"Jan Tymll",
"Zacker Tz",
"Zoltán Tóth",
"Buğra Türksal",
"uDinnoo",
"Cristian Ugalde",
"Atchy-Dalama--Ancelly Ulrich",
@ -1663,9 +1747,11 @@
"Tommy Wong",
"WonkaWoe",
"Moury ji world",
"worldbiomusic",
"wsltshh",
"Wurstkatze",
"WurstSaft",
"WynB",
"Xavier",
"Francisco Xavier",
"xbarix123897",
@ -1682,6 +1768,7 @@
"Halil Yarkin",
"Yaroslav (Spaz1)",
"amr yasser",
"Yatoku",
"YellowTractor",
"Yasin YILMAZ",
"Ymgfr",
@ -1717,10 +1804,12 @@
"ZaraMax",
"zecharaiah",
"Daniele Zennaro",
"zFliws",
"zfuw668",
"Alex Zhao",
"Doge Zhao",
"Riven Zhao",
"Liubomyr Zheltova",
"jim ZHOU",
"Mohammad ziar",
"ZioFesteeeer",
@ -1737,6 +1826,7 @@
"Cristian Țicu",
"Μπαρλάς Παύλος-Ιάσονας",
"Ανέστης Πλήθος",
"Яркин Абдулхалил",
"Роман Абрамо",
"Роман Абрамов",
"Андрей (Krays)",
@ -1751,6 +1841,7 @@
"Дмитрий 228",
"Евгений(Eugene)",
"Артём Зобков (KoLenka)",
"Иван",
"Юстин Иглин",
"Игор",
"Кирилл",
@ -1779,6 +1870,7 @@
"Кирилл Рябцев",
"Ерасыл Фазылов (Paraxilius)",
"ZEPT\"Александр Фартунов\"",
"!SW сосут мой член!",
"Эмир",
"Өмүрзаков Эрсултан",
"Ярослав \"Noiseaholic\"",
@ -1807,6 +1899,7 @@
"امید رضازاده",
"فاطمه عباس زاده ۸۴",
"فاطمه عباس زاده۸۴",
"زينب",
"ستسپ",
"سلطان سروش",
"محمد وائل سلطان",
@ -1856,6 +1949,7 @@
"南宫銷子()",
"哔哩哔哩@Medic药",
"夏神(后期汉化修正)",
"大笨蛋susu",
"小黑猫",
"张帅",
"徐安博",
@ -1886,6 +1980,7 @@
"넌",
"먹꾸리",
"박건희",
"배추",
"김대중 부관참시",
"붐추",
"사람사는 세상",
@ -1896,6 +1991,7 @@
"BombsquadKorea 네이버 카페",
"Zona-BombSquad",
"CrazySquad",
"Stazzy"
"Stazzy",
"Slida"
]
}

View file

@ -1,6 +1,6 @@
{
"accountSettingsWindow": {
"accountNameRules": "لا يمكن لاسماء الحِسابَات أن تحتوي على رموز تعبيرية أو حروف غير ألفبائية",
"accountNameRules": ".لا يمكن لاسماء الحِسابَات أن تحتوي على رموز تعبيرية أو حروف غير ألفبائية",
"accountProfileText": "معلومات اللاعبين",
"accountsText": "حسابات",
"achievementProgressText": "${TOTAL} من أصل ${COUNT} إنجازاتك: أنجزت",
@ -31,6 +31,7 @@
"signInWithGooglePlayText": "Google Play سجل دخولك عبر ",
"signInWithTestAccountInfoText": "(حساب موجود على هاتفك; استخدم حساب الهاتف للمتابعة)",
"signInWithTestAccountText": "تسجيل الدخول بحساب تجريبي",
"signInWithText": "تسجيل دخول مع ${SERVICE}",
"signInWithV2InfoText": "حساب يعمل على جميع المنصات",
"signInWithV2Text": "قم بتسجيل الدخول باستخدام حساب BombSquad",
"signOutText": "تسجيل الخروج",
@ -369,6 +370,7 @@
"chatMutedText": "تم اسكات الدردشة",
"chatUnMuteText": "تحرير الدردشة",
"choosingPlayerText": "<يختار لاعب>",
"codesExplainText": "يتم توفير الرموز من قبل المطور\n.لتحليل مشاكل الحساب وتصحيحها",
"completeThisLevelToProceedText": "يجب أن تكمل هذه المرحلة ليتم الاجراء",
"completionBonusText": "علاوة الاكمال",
"configControllersWindow": {
@ -449,6 +451,7 @@
"swipeText": "مسحة",
"titleText": "تهيئة شاشة اللمس"
},
"configureDeviceInSystemSettingsText": "${DEVICE} يُمكن تعديله في تطبيق إعدادات النظام.",
"configureItNowText": "هل تريد تهيئته الآن؟",
"configureText": "تهيئة",
"connectMobileDevicesWindow": {
@ -810,7 +813,7 @@
"youHaveShortText": "لديك ${COUNT}",
"youHaveText": "لديك ${COUNT} تذاكر"
},
"googleMultiplayerDiscontinuedText": "عذرًا ، خدمة جوجل متعددة اللاعبين لم تعد متاحة.\n أنا أعمل على بديل بأسرع وقت ممكن.\n حتى ذلك الحين ، يرجى تجربة طريقة اتصال أخرى.\n -إريك",
"googleMultiplayerDiscontinuedText": "\nعذرًا ، خدمة جوجل متعددة اللاعبين لم تعد متاحة.\n أنا أعمل على بديل بأسرع وقت ممكن.\n حتى ذلك الحين ، يرجى تجربة طريقة اتصال أخرى.\n -إريك",
"googlePlayPurchasesNotAvailableText": "عمليات شراء جوجل بلاي غير متوفرة.\nقد تحتاج لتحديث تطبيق المتجر.",
"googlePlayServicesNotAvailableText": "غوغل بلاي العاب غير متوفر.\nبعض المزايا لن تكون متوفرة.",
"googlePlayText": "جوجل بلاي",
@ -818,10 +821,12 @@
"alwaysText": "دائما",
"fullScreenCmdText": "ملء الشاشة (Cmd-F)",
"fullScreenCtrlText": "الشاشه كامله (Ctrl-F)",
"fullScreenText": "تكبير الشاشة",
"gammaText": "غاما",
"highText": "عالي الدقة",
"higherText": "العالي",
"lowText": "منخفض",
"maxFPSText": "أعلى معدل إطارات",
"mediumText": "متوسط",
"neverText": "أبدا",
"resolutionText": "القرار",
@ -1060,6 +1065,7 @@
"noExternalStorageErrorText": "لم يتم العثور على وحدة تخزين خارجية على هذا الجهاز",
"noGameCircleText": "خطأ: لم يتم تسجيل الدخول الئ gamecircle",
"noScoresYetText": "لا نقاط حتى الآن.",
"noServersFoundText": "لا توجد اي سيرفرات.",
"noThanksText": "لا شكرا",
"noTournamentsInTestBuildText": "تحذير: سيتم تجاهل نقاط البطولات في النسخة التجريبية",
"noValidMapsErrorText": "لا خرائط صالحة وجدت لهذا النوع اللعبة.",
@ -1269,6 +1275,7 @@
"netTestingText": "اختبار الشبكة",
"resetText": "إعادة تعيين",
"showBombTrajectoriesText": "عرض مسارات القنبلة",
"showDevConsoleButtonText": "إظهار زر وحدة تحكم المطورين",
"showInGamePingText": "عرض التأخير الداخلي للعبة",
"showPlayerNamesText": "إظهار اسماء اللاعبين",
"showUserModsText": "عرض مجلد التعديل",
@ -1360,6 +1367,8 @@
"storeText": "متجر",
"submitText": "ارسال",
"submittingPromoCodeText": "تقديم الكود ...",
"successText": "نجحت!",
"supportEmailText": "ايذا لديك اي مشكلة تقنية مع\nالبرنامح, يرجى استخدام البريد إلكتروني للدعم ${EMAIL}.",
"teamNamesColorText": "اسماء/الوان الفرق...",
"telnetAccessGrantedText": "تم تمكين الوصول تلنيت.",
"telnetAccessText": "تم الكشف عن الوصول تلنيت. السماح؟",
@ -1813,6 +1822,7 @@
"unlockThisInTheStoreText": "هذا يجب ان يفتح في المتجر",
"unlockThisProfilesText": "لإنشاء أكثر من ${NUM} من الملفات الشخصية، تحتاج إلى:",
"unlockThisText": ":لفتح هذا, تحتاج إلى",
"unsupportedControllerText": "عذرًا، وحدة التحكم \"${NAME}\" غير مدعومة.",
"unsupportedHardwareText": "عفوا, هذه المعدات غير مدعومة في هذه النسخة من اللعبة",
"upFirstText": ":يصل اولا",
"upNextText": ":${COUNT}التالي في اللعبة",
@ -1824,6 +1834,7 @@
"usingItunesText": "...استخدام تطبيق الموسيقى للموسيقى التصويرية",
"v2AccountLinkingInfoText": "اذا اردت ربط حسابات V2، قم بالتوجه الى 'ادارة الحساب'.",
"validatingTestBuildText": "التحقق من صحة البناء",
"viaText": "عبر",
"victoryText": "!النصر",
"voteDelayText": "ثانية ${NUMBER} لا يمكنك التصويت ثانية حتى",
"voteInProgressText": "التصويت بالفعل في التقدم",

View file

@ -30,6 +30,7 @@
"signInWithGooglePlayText": "Увайсці з дапамогаю Google Play",
"signInWithTestAccountInfoText": "(акаўнт, які ўжо існуе; спачатку увайдзіце з прылады)",
"signInWithTestAccountText": "Увайсці з тэст-акаўнта",
"signInWithText": "Увайдзіце з дапамогай ${SERVICE}",
"signInWithV2InfoText": "(уліковы запіс, які працуе на ўсіх платформах)",
"signInWithV2Text": "Увайдзіце з уліковым запісам BombSquad",
"signOutText": "Выйсці",
@ -369,6 +370,7 @@
"chatMutedText": "Чат адключон",
"chatUnMuteText": "Уключыць гук у чаце",
"choosingPlayerText": "<выбар гульца>",
"codesExplainText": "Коды прадастаўляюцца распрацоўшчыкам\nдыягностыка і выпраўленне праблем з уліковым запісам.",
"completeThisLevelToProceedText": "Вы павінны прайсці гэты\nўзровень, каб працягнуць!",
"completionBonusText": "Бонус за праходжанне",
"configControllersWindow": {
@ -449,6 +451,7 @@
"swipeText": "змахванне",
"titleText": "Налады Экрана"
},
"configureDeviceInSystemSettingsText": "${DEVICE} можна наладзіць у праграме \"Сістэмныя налады\".",
"configureItNowText": "Наладзіць гэта зараз?",
"configureText": "Налады",
"connectMobileDevicesWindow": {
@ -562,6 +565,8 @@
"disableXInputDescriptionText": "Дазваляе больш за 4 кантролераў, але можа таксама не працаваць.",
"disableXInputText": "Адключыць XInput",
"disabledText": "Выключана",
"discordFriendsText": "Хочаце шукаць новых людзей для гульні?\nДалучайцеся да нашага Discord і знайдзіце новых сяброў!",
"discordJoinText": "Далучайцеся да Discord",
"doneText": "Зроблена",
"drawText": "Нічыя",
"duplicateText": "Дублікат",
@ -823,10 +828,12 @@
"alwaysText": "Заўсёды",
"fullScreenCmdText": "Поўнаэкранны (Сmd-F)",
"fullScreenCtrlText": "Поўнаэкранны (Ctrl-F)",
"fullScreenText": "На ўвесь экран",
"gammaText": "Гама",
"highText": "Высокае",
"higherText": "Найвышэйшае",
"lowText": "Нізкае",
"maxFPSText": "Самы высокі FPS",
"mediumText": "Сярэдняе",
"neverText": "Ніколі",
"resolutionText": "Дазвол",
@ -1068,6 +1075,7 @@
"noGameCircleText": "Памылка: вы не ўвайшлі ў GameCircle",
"noProfilesErrorText": "У вас няма ніводнага профіля, таму вас будуць называць '${NAME}'.\nЗайдзіце ў \"Налады -> Профілі\", каб стварыць уласны профіль.",
"noScoresYetText": "Вынікаў пакуль няма.",
"noServersFoundText": "Серверы не знойдзены.",
"noThanksText": "Не, дзякуй",
"noTournamentsInTestBuildText": "УВАГА: Ацэнкі турніраў з гэтай тэставай зборкі будуць ігнаравацца.",
"noValidMapsErrorText": "Не знойдзена мап для гэтага тыпу гульні.",
@ -1279,6 +1287,7 @@
"netTestingText": "Тэсціраванне Сеткі",
"resetText": "Скінуць",
"showBombTrajectoriesText": "Паказваць Траекторыi Бомб",
"showDevConsoleButtonText": "Паказаць Кнопку Кансолі Распрацоўніка",
"showInGamePingText": "Паказываць Пынг Гульні",
"showPlayerNamesText": "Паказваць Імёны Гульцоў",
"showUserModsText": "Паказаць Тэчку З Модамі",
@ -1373,6 +1382,8 @@
"storeText": "Крама",
"submitText": "Адправіць",
"submittingPromoCodeText": "Адпраўка кода...",
"successText": "Паспяхова!",
"supportEmailText": "Калі ў вас узніклі праблемы з\nпрыкладаннем, калі ласка, напішыце ${EMAIL}.",
"teamNamesColorText": "Назвы / колеры каманд ...",
"telnetAccessGrantedText": "Доступ Telnet уключаны.",
"telnetAccessText": "Знойдзены доступ Telnet, дазволіць?",
@ -1438,12 +1449,12 @@
"${GAME} Training": "Падрыхтоўка да гульні ${GAME}",
"Infinite ${GAME}": "Бясконцая ${GAME}",
"Infinite Onslaught": "Бясконцая Атака",
"Infinite Runaround": "Бясконцы Манеўр",
"Infinite Runaround": "Бясконцая бегатня",
"Onslaught Training": "Атака: Трэніроўка",
"Pro ${GAME}": "${GAME} Профі",
"Pro Football": "Футбол Профі",
"Pro Onslaught": "Атака Профі",
"Pro Runaround": "Манёўр Профі",
"Pro Runaround": "Бегатня Профі",
"Rookie ${GAME}": "${GAME} Лёгкі",
"Rookie Football": "Футбол Лёгкі",
"Rookie Onslaught": "Атака Лёгкая",
@ -1451,7 +1462,7 @@
"Uber ${GAME}": "Убер ${GAME}",
"Uber Football": "Убер Футбол",
"Uber Onslaught": "Убер Атака",
"Uber Runaround": "Убер Манёўр"
"Uber Runaround": "Убер Бегатня"
},
"gameDescriptions": {
"Be the chosen one for a length of time to win.\nKill the chosen one to become it.": "Каб перамагчы, стань абраным на некаторы час.\nКаб стаць абраным, забей мінулага абранага.",
@ -1829,6 +1840,7 @@
"unlockThisInTheStoreText": "Гэта павінна быць адкрыта ў магазіне.",
"unlockThisProfilesText": "Каб стварыць больш за ${NUM} профіляў, вам трэба:",
"unlockThisText": "Каб адкрыць гэта, вам патрэбна:",
"unsupportedControllerText": "На жаль, кантролер \"${NAME}\" не падтрымліваецца.",
"unsupportedHardwareText": "Прабачце, ваша прылада не падтрымлівае гэтую версію гульні.",
"upFirstText": "Спачатку:",
"upNextText": "Далей у гульні ${COUNT}:",
@ -1841,6 +1853,7 @@
"usingItunesTurnRepeatAndShuffleOnText": "Калі ласка, праверце, што ператасаванне і паўтор усяго ў iTunes ўключаны. ",
"v2AccountLinkingInfoText": "Да прывязкі акаўнту V2, Нажміце 'Кіраваць акаўнтамі'.",
"validatingTestBuildText": "Праверка Тэставай Зборкі...",
"viaText": "праз",
"victoryText": "Перамога!",
"voteDelayText": "Вы не можаце пачаць яшчэ адно галасаванне на працягу ${NUMBER} секунд",
"voteInProgressText": "Галасаванне ўжо ідзе.",

View file

@ -24,16 +24,17 @@
"resetProgressText": "重置游戏进程",
"setAccountName": "设置账户名称",
"setAccountNameDesc": "选择要为您的帐户显示的名称。\n您可以从链接的帐户选择\n或创建唯一的自定义名称。",
"signInInfoText": "登以获取点券, 在线竞赛,\n并在不同设备上同步游戏进程。",
"signInInfoText": "登以获取点券, 在线竞赛,\n并在不同设备上同步游戏进程。",
"signInText": "登陆",
"signInWithDeviceInfoText": "(仅适用于此设备的一个自动账户)",
"signInWithDeviceText": "用设备账户来登",
"signInWithDeviceText": "用设备账户来登",
"signInWithGameCircleText": "使用 Game Circle 登入",
"signInWithGooglePlayText": "用 Google Play 来登",
"signInWithGooglePlayText": "用 Google Play 来登",
"signInWithTestAccountInfoText": "使用设备上的其他网络帐号登录;不建议选择该项",
"signInWithTestAccountText": "用测试账户来登陆",
"signInWithText": "使用 ${SERVICE} 登录",
"signInWithV2InfoText": "(账户在所有平台都通用)",
"signInWithV2Text": "使用炸弹小分队账号登录",
"signInWithV2Text": "使用炸V2账号登录",
"signOutText": "登出",
"signingInText": "登录中...",
"signingOutText": "登出中...",
@ -42,8 +43,8 @@
"ticketsText": "点券:${COUNT}",
"titleText": "账号",
"unlinkAccountsInstructionsText": "选择要取消关联的帐户",
"unlinkAccountsText": "取消连结帐户",
"unlinkLegacyV1AccountsText": "取消连接旧版V1账户",
"unlinkAccountsText": "取帐户",
"unlinkLegacyV1AccountsText": "取消关联旧版V1账户",
"v2LinkInstructionsText": "扫码或使用链接来登录或注册新账户",
"viaAccount": "(不可用名称 ${NAME})",
"youAreLoggedInAsText": "您已登录为",
@ -64,7 +65,7 @@
"descriptionComplete": "没有使用任何炸弹就获胜了",
"descriptionFull": "在${LEVEL}中不用炸弹获胜",
"descriptionFullComplete": "在${LEVEL}中没用炸弹就获胜了",
"name": "拳"
"name": "拳"
},
"Dual Wielding": {
"descriptionFull": "连接两个控制手柄(硬件或应用)",
@ -95,7 +96,7 @@
"descriptionComplete": "没有用炸弹或拳头攻击就获胜了",
"descriptionFull": "在${LEVEL}中不用炸弹或拳头攻击就获胜",
"descriptionFullComplete": "在${LEVEL}中没有用炸弹或拳头攻击就获胜了",
"name": "位是关键"
"name": "位是关键"
},
"In Control": {
"descriptionFull": "连接一个控制手柄(硬件或应用)",
@ -371,6 +372,7 @@
"chatMutedText": "聊天静音",
"chatUnMuteText": "取消屏蔽消息",
"choosingPlayerText": "<选择玩家>",
"codesExplainText": "开发者会提供代码来\n诊断和修复账户问题",
"completeThisLevelToProceedText": "你需要先完成这一关",
"completionBonusText": "完成奖励",
"configControllersWindow": {
@ -451,6 +453,7 @@
"swipeText": "滑动",
"titleText": "触摸屏配置"
},
"configureDeviceInSystemSettingsText": "${DEVICE} 可以在系统设置中配置捏",
"configureItNowText": "立即配置?",
"configureText": "配置",
"connectMobileDevicesWindow": {
@ -564,6 +567,8 @@
"disableXInputDescriptionText": "允许使用4个以上的控制器但可能不会正常工作",
"disableXInputText": "禁用XInput",
"disabledText": "禁用",
"discordFriendsText": "这是官方Discord群的按钮但是很可惜中国不许你用Discord\n所以来加鲨鱼QQ群902867245吧译者注有问题可改",
"discordJoinText": "我就要加Discord",
"doneText": "完成",
"drawText": "平局",
"duplicateText": "复制",
@ -642,7 +647,7 @@
"errorDeviceTimeIncorrectText": "您设备的时间有 ${HOURS} 小时的误差。\n这会导致游戏出现问题。\n请检查您设备的时间和时区设置。",
"errorOutOfDiskSpaceText": "磁盘空间不足",
"errorSecureConnectionFailText": "无法建立安全的云链接,网络可能会连接失败",
"errorText": "错误",
"errorText": "啊呜,好像出错了喵...",
"errorUnknownText": "未知错误",
"exitGameText": "退出${APP_NAME}",
"exportSuccessText": "退出'${NAME}'",
@ -655,7 +660,7 @@
"titleFolderText": "选择一个文件夹",
"useThisFolderButtonText": "使用此文件夹"
},
"filterText": "过滤器",
"filterText": "搜索",
"finalScoreText": "最后得分",
"finalScoresText": "最后得分",
"finalTimeText": "最终时间",
@ -733,7 +738,7 @@
"hostingUnavailableText": "主机不可用",
"inDevelopmentWarningText": "注意:\n\n联网模式是一项新的并且还在开发特性\n目前强烈建议所有玩家在同一个\n无线局域网下游戏。",
"internetText": "在线游戏",
"inviteAFriendText": "好友还未加入该游戏?邀请他们\n一起玩新玩家可获得${COUNT}张免费点券。",
"inviteAFriendText": "你的朋友还没下载?邀请他们\n一起玩新玩家可获得${COUNT}张免费点券。",
"inviteFriendsText": "邀请朋友",
"joinPublicPartyDescriptionText": "加入一个公开派对",
"localNetworkDescriptionText": "加入一个局域网派对(通过wifi蓝牙等各种方式)",
@ -825,17 +830,19 @@
"alwaysText": "总是",
"fullScreenCmdText": "全屏显示Cmd+F",
"fullScreenCtrlText": "全屏(Ctrl-F)",
"fullScreenText": "全屏",
"gammaText": "Gamma",
"highText": "高",
"higherText": "极高",
"lowText": "低",
"maxFPSText": "最高帧数",
"mediumText": "中",
"neverText": "关",
"resolutionText": "分辨率",
"showFPSText": "显示FPS帧数",
"texturesText": "材质质量",
"titleText": "图像质量",
"tvBorderText": "电视边缘",
"tvBorderText": "大广角",
"verticalSyncText": "垂直同步",
"visualsText": "视觉"
},
@ -845,15 +852,15 @@
"controllersInfoText": "你可以和好友在同一网络下玩${APP_NAME},或者\n如果你有足够多的手柄那也可以在同一个设备上游戏。\n${APP_NAME}支持各种选择;你甚至可以通过免费的'${REMOTE_APP_NAME}'\n用手机作为游戏手柄。\n更多信息请参见设置->手柄。",
"controllersInfoTextRemoteOnly": "你可以通过局域网与你的朋友们一起游玩${APP_NAME}\n或者你可以使用${REMOTE_APP_NAME}\n它会将你的手机作为手柄在同一个设备上与你的朋友一起游玩",
"controllersText": "手柄",
"controlsSubtitleText": "你的友好的${APP_NAME}角色具有几个基本动作",
"controlsSubtitleText": "${APP_NAME}的角色基本操作如下",
"controlsText": "控制键",
"devicesInfoText": "VR版${APP_NAME}可与\n普通版本联网游戏所以掏出你所有的手机、平板电脑\n和电脑大玩一场吧。你甚至还可以将\n普通版本的游戏连接至VR版\n让游戏外的人也能看你玩。",
"devicesText": "设备",
"friendsGoodText": "这对你而言都是好事。和三五好友一起玩${APP_NAME}最有趣了,\n最多可以支持8个玩家一起玩进入",
"friendsGoodText": "哎,一个人玩?那咋行!${APP_NAME}就是要人多才好玩嘛~\n最多支持8人同时游戏如果你有魔法可以改掉限制喵~快拉你的小伙伴一起玩吧",
"friendsText": "好友",
"jumpInfoText": "跳跃\n跳跃可以跳过较窄的缝隙,\n或是把炸弹扔的更远,\n或是表达你难以掩盖的喜悦之情。",
"jumpInfoText": "跳跃\n跳跃可以跳过小沟,\n或是把炸弹扔得更远,\n或是表达你难以掩盖的喜悦之情。",
"orPunchingSomethingText": "还可以用拳头攻击,或者把敌人举起来然后丢下去,或者更多好玩的...",
"pickUpInfoText": "拾起\n你可以拾起旗子敌人\n还有所有没固定在地上的东西\n然后再扔出去吧",
"pickUpInfoText": "拾起\n你可以拾起旗子敌人\n还有所有没固定在地上的东西\n然后再扔出去吧~",
"powerupBombDescriptionText": "将炸弹最大投掷数量\n由一个提升为三个",
"powerupBombNameText": "三连炸弹",
"powerupCurseDescriptionText": "最好不要接触它。\n...或者你想试试?",
@ -875,7 +882,7 @@
"powerupsSubtitleText": "当然,没有道具的游戏很难通关:",
"powerupsText": "道具",
"punchInfoText": "拳击\n跑得越快拳击的伤害\n越高。所以像疯子一样\n旋转跳跃吧",
"runInfoText": "冲刺\n按任意键冲刺,如果你用手柄操作将会容易许多。\n冲刺跑的虽快但会造成转向困难。且冲且珍惜。",
"runInfoText": "冲刺\n按住四个键中的一个即可冲刺,如果你用手柄可以将扳机设置为跑\n冲刺跑的虽快但会造成转向困难。且冲且珍惜",
"someDaysText": "当你想攻击别人时,你可以用各种炸弹",
"titleText": "${APP_NAME}帮助",
"toGetTheMostText": "要想最痛快地玩这个游戏,你需要:",
@ -937,7 +944,7 @@
"rejectingInviteAlreadyInPartyText": "拒绝邀请(已经在派对中)。",
"serverRestartingText": "服务器自动重启中,请重新加入..",
"serverShuttingDownText": "服务器正在关机…",
"signInErrorText": "登出错啦~",
"signInErrorText": "登出错啦~",
"signInNoConnectionText": "哎呀,无法登陆。(网络连接有故障?)",
"telnetAccessDeniedText": "错误用户未得到telnet访问授权。",
"timeOutText": "(将在${TIME}秒内超出时限)",
@ -1036,7 +1043,7 @@
"mapSelectTitleText": "${GAME}地图",
"mapText": "地图",
"maxConnectionsText": "最大连接数",
"maxPartySizeText": "最大派对规模",
"maxPartySizeText": "最大派对人数",
"maxPlayersText": "最多人数",
"merchText": "来买周边吧~",
"modeArcadeText": "街机模式",
@ -1059,7 +1066,7 @@
"nameText": "名称",
"nativeText": "本机",
"newPersonalBestText": "新个人记录!",
"newTestBuildAvailableText": "更新的测试版可供下载了!(${VERSION}生成${BUILD})。\n到${ADDRESS}获取",
"newTestBuildAvailableText": "更新的测试版可供下载了!(${VERSION} build${BUILD})。\n到${ADDRESS}获取吧!",
"newText": "新建",
"newVersionAvailableText": "更新版本的 ${APP_NAME} 可供下载了! 版本号(${VERSION})",
"nextAchievementsText": "下一个成就:",
@ -1070,6 +1077,7 @@
"noGameCircleText": "错误未登入GameCircle",
"noProfilesErrorText": "您没有玩家档案,所以还得忍受“${NAME}”这个名字。\n进入设置->玩家档案,为自己创建档案。",
"noScoresYetText": "还未有得分记录。",
"noServersFoundText": "未找到服务器",
"noThanksText": "不,谢谢",
"noTournamentsInTestBuildText": "温馨提示:测试版的锦标赛分数不能计入锦标赛哦!",
"noValidMapsErrorText": "该比赛类型中未发现有效地图。",
@ -1140,7 +1148,7 @@
"pleaseRateText": "如果你喜欢 ${APP_NAME},请考虑花一点时间\n来评价一下它或为它写一篇评论。这将为我们提供\n有用的反馈建议为游戏的未来开发给予支持。\n\n感谢您\n-eric",
"pleaseWaitText": "请稍等...",
"pluginClassLoadErrorText": "加载'${PLUGIN}'插件时出错了耶: ${ERROR}",
"pluginInitErrorText": "初始化'${PLUGIN}'插件失败了: ${ERROR}",
"pluginInitErrorText": "初始化'${PLUGIN}'插件失败了: ${ERROR}",
"pluginSettingsText": "插件设置",
"pluginsAutoEnableNewText": "自动启用新插件",
"pluginsDetectedText": "新插件安装成功,请重启游戏或在设置中设置它们~",
@ -1284,6 +1292,7 @@
"netTestingText": "网络测试",
"resetText": "恢复默认值",
"showBombTrajectoriesText": "显示炸弹轨迹",
"showDevConsoleButtonText": "显示开发者控制台按钮",
"showInGamePingText": "显示游戏延迟",
"showPlayerNamesText": "显示玩家名字",
"showUserModsText": "显示Mod文件夹",
@ -1378,6 +1387,8 @@
"storeText": "商店",
"submitText": "提交",
"submittingPromoCodeText": "正在提交代码...",
"successText": "成功",
"supportEmailText": "如果你在APP遇到任何问题\n请发邮件到${EMAIL}",
"teamNamesColorText": "团队名称/颜色。。。",
"telnetAccessGrantedText": "Telnet访问已启用。",
"telnetAccessText": "检测到Telnet访问是否允许",
@ -1648,7 +1659,7 @@
"Profile \"${NAME}\" upgraded successfully.": "${NAME}档案升级成功。",
"Profile could not be upgraded.": "档案不可升级。",
"Purchase successful!": "购买成功!",
"Received ${COUNT} tickets for signing in.\nCome back tomorrow to receive ${TOMORROW_COUNT}.": "登录成功 获得${COUNT}点券喵~\n明日再来领取${TOMORROW_COUNT}。",
"Received ${COUNT} tickets for signing in.\nCome back tomorrow to receive ${TOMORROW_COUNT}.": "今日登录获得${COUNT}点券\n明日再来领取${TOMORROW_COUNT}点券",
"Server functionality is no longer supported in this version of the game;\nPlease update to a newer version.": "此版本的游戏不再支持服务器功能;\n请更新到较新版本。",
"Sorry, there are no uses remaining on this code.": "对不起,此代码已经无法继续使用了。",
"Sorry, this code has already been used.": "对不起,此代码已被使用。",
@ -1663,9 +1674,9 @@
"This requires version ${VERSION} or newer.": "这需要版本${VERSION}或更高版本。",
"Tournaments disabled due to rooted device.": "该设备已禁用比赛。",
"Tournaments require ${VERSION} or newer": "比赛需要${VERSION}或更高版本",
"Unlink ${ACCOUNT} from this account?\nAll data on ${ACCOUNT} will be reset.\n(except for achievements in some cases)": "从此帐户取消 ${ACCOUNT} 的连结\n${ACCOUNT}上的所有数据将被重置。\n在某些情况下除成就外",
"Unlink ${ACCOUNT} from this account?\nAll data on ${ACCOUNT} will be reset.\n(except for achievements in some cases)": "从此帐户取消 ${ACCOUNT} 的关联\n${ACCOUNT}上的所有数据将被重置。\n在某些情况下除成就外",
"WARNING: complaints of hacking have been issued against your account.\nAccounts found to be hacking will be banned. Please play fair.": "警告:针对您的帐户发出黑客投诉。\n被盗用的帐户将被禁止。请公平竞技。",
"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": "是否将您的设备帐户链接到此?\n\n您的设备账户为${ACCOUNT1}\n此帐户为${ACCOUNT2}\n\n您可保存现有进度。\n警告: 此操作不可撤消!",
"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": "是否将您的设备帐户关联到此?\n\n您的设备账户为${ACCOUNT1}\n此帐户为${ACCOUNT2}\n\n您可保存现有进度。\n警告: 此操作不可撤消!",
"You already own this!": "你已拥有了!",
"You can join in ${COUNT} seconds.": "你在${COUNT} 秒后可以加入",
"You don't have enough tickets for this!": "你的点券不足!",
@ -1832,6 +1843,7 @@
"unlockThisInTheStoreText": "这必须在商店中解锁。",
"unlockThisProfilesText": "如需创建超过 ${NUM} 个玩家档案,你需要",
"unlockThisText": "你需要这些来解锁",
"unsupportedControllerText": "抱歉,游戏不兼容你的控制器\"${NAME}\"",
"unsupportedHardwareText": "抱歉,此版本的游戏不支持该硬件。",
"upFirstText": "进入第一局:",
"upNextText": "进入比赛${COUNT}第二局:",
@ -1842,8 +1854,9 @@
"usesExternalControllerText": "该游戏使用外部手柄进行输入。",
"usingItunesText": "使用音乐应用设置背景音乐……",
"usingItunesTurnRepeatAndShuffleOnText": "请确认iTunes中随机播放已开启且重复全部歌曲。",
"v2AccountLinkingInfoText": "要连接V2账户请点击“管理账户”~",
"v2AccountLinkingInfoText": "要关联V2账户请点击“管理账户”喵~",
"validatingTestBuildText": "测试版验证中……",
"viaText": "渠道账户:",
"victoryText": "胜利!",
"voteDelayText": "${NUMBER} 秒内你不能发起另一个投票",
"voteInProgressText": "已经有一个投票在进行中了",

View file

@ -818,6 +818,7 @@
"highText": "高",
"higherText": "最高",
"lowText": "低",
"maxFPSText": "最大FPS",
"mediumText": "中",
"neverText": "關",
"resolutionText": "分辨率",
@ -1265,6 +1266,7 @@
"netTestingText": "網絡連接測試",
"resetText": "恢復默認",
"showBombTrajectoriesText": "顯示炸彈軌跡",
"showDevConsoleButtonText": "顯示開發控制臺按鈕",
"showInGamePingText": "顯示遊戲內延遲",
"showPlayerNamesText": "顯示玩家名稱",
"showUserModsText": "顯示MOD安裝文件夾",

View file

@ -32,6 +32,7 @@
"signInWithGooglePlayText": "Přihlásit se přes Google Play",
"signInWithTestAccountInfoText": "(zastaralý typ účtu; použije raději účet zařízení)",
"signInWithTestAccountText": "Přihlásit se s testovacím účtem",
"signInWithText": "Přihlásit se s ${SERVICE}",
"signInWithV2InfoText": "(účet který funguje na všech platformách)",
"signInWithV2Text": "Přihlášení s BombSquad účtem",
"signOutText": "Odhlásit se",
@ -339,6 +340,8 @@
"getMoreGamesText": "Získat více her...",
"titleText": "Přidat hru"
},
"addToFavoritesText": "Přidáno do Oblíbených",
"addedToFavoritesText": "Přidáno '${NAME}' do Oblíbených.",
"allText": "Vše",
"allowText": "Povolit",
"alreadySignedInText": "Tento účet je používán v jiném zařízení;\npřepněte prosím účet nebo v druhém\nzařízení hru zavřete, poté to zkuste znova.",
@ -375,6 +378,7 @@
"chatMutedText": "Chat ztlumen",
"chatUnMuteText": "Obnovit chat",
"choosingPlayerText": "<vybírá hráče>",
"codesExplainText": "Kódy jsou zřizovány vývojářem za účelem\ndiagnózy a opravy problémů s účty.",
"completeThisLevelToProceedText": "Musíte dokončit\ntento level, abyste mohli pokračovat!",
"completionBonusText": "Bonus za dokončení",
"configControllersWindow": {
@ -455,6 +459,7 @@
"swipeText": "přejíždění",
"titleText": "Nastavit dotykovou obrazovku"
},
"configureDeviceInSystemSettingsText": "${DEVICE} může být nakonfigurováno v Nastavení Systému",
"configureItNowText": "Nastavit teď?",
"configureText": "Nastavit",
"connectMobileDevicesWindow": {
@ -568,6 +573,8 @@
"disableXInputDescriptionText": "Povolí více než 4 ovladače, ale nemusí fungovat tak dobře.",
"disableXInputText": "Vypnout XInput",
"disabledText": "Zakázáno",
"discordFriendsText": "Chcete najít nové lidi na hraní?\nPřipojte se k našemu Discordu a najděte nové přátele!",
"discordJoinText": "Připoj se k Discordu",
"doneText": "Hotovo",
"drawText": "Remíza",
"duplicateText": "Duplikovat",
@ -756,6 +763,7 @@
"manualYourLocalAddressText": "Vaše lokální adresa:",
"nearbyText": "Lokální",
"noConnectionText": "<žádné připojení>",
"noPartiesAddedText": "Nebyly přidány žádné strany",
"otherVersionsText": "(ostatní verze)",
"partyCodeText": "Kód Party",
"partyInviteAcceptText": "Potvrdit",
@ -828,10 +836,12 @@
"alwaysText": "Vždy",
"fullScreenCmdText": "Celá obrazovka (Cmd-F)",
"fullScreenCtrlText": "Celá obrazovka (Ctrl-F)",
"fullScreenText": "Na celou obrazovku",
"gammaText": "Gamma",
"highText": "Vysoká",
"higherText": "Vyšší",
"lowText": "Nízká",
"maxFPSText": "Maximální FPS",
"mediumText": "Střední",
"neverText": "Nikdy",
"resolutionText": "Rozlišení",
@ -1071,8 +1081,10 @@
"noContinuesText": "(bez pokračování)",
"noExternalStorageErrorText": "Žádné externí úložiště nebylo na tomto zařízení nalezeno",
"noGameCircleText": "Chyba: nejste přihlášeni do Game Circle",
"noPluginsInstalledText": "Nenainstalovány žádné pluginy",
"noProfilesErrorText": "Nemáte žádné herní profily, takže Vám bylo podstrčeno jméno '${NAME}'.\nJděte do Nastavení->Herní Profily pro vytvoření svého profilu.",
"noScoresYetText": "Zatím žádné výsledky.",
"noServersFoundText": "Nenalezeny žádné servery.",
"noThanksText": "Ne, děkuji",
"noTournamentsInTestBuildText": "VAROVÁNÍ: Skóre z turnajů z tohoto testovacího buildu budou ignorovány.",
"noValidMapsErrorText": "Nebyly nalezeny žádné platné mapy pro tento typ hry.",
@ -1285,6 +1297,7 @@
"netTestingText": "Testování sítě",
"resetText": "Obnovit",
"showBombTrajectoriesText": "Ukazovat trajektorii bomb",
"showDevConsoleButtonText": "Ukaž tlačítko vývojářské konzoly",
"showInGamePingText": "Ukazovat ping při hře",
"showPlayerNamesText": "Ukazovat jména hráčů",
"showUserModsText": "Zobrazit složku s módy",
@ -1379,6 +1392,8 @@
"storeText": "Obchod",
"submitText": "Odeslat",
"submittingPromoCodeText": "Odesílám kód...",
"successText": "Úspěch!",
"supportEmailText": "Pokud máte jakékoliv problémy s aplikací, prosím \nnapište na email ${EMAIL}.",
"teamNamesColorText": "Jména/Barvy týmů...",
"telnetAccessGrantedText": "Přístup k telnetu zapnut.",
"telnetAccessText": "Detekován přístup k telnetu; povolit?",
@ -1833,6 +1848,7 @@
"unlockThisInTheStoreText": "Toto musí být nejdříve odemknuto v obchodě.",
"unlockThisProfilesText": "Pro vytvoření více než ${NUM} profilů, potřebujete:",
"unlockThisText": "Pro odemknutí tohoto potřebujete:",
"unsupportedControllerText": "Je mi líto, ovladač \"${NAME}\" není podporován.",
"unsupportedHardwareText": "Omlouváme se, ale tento hardware není porporován tímto buildem hry.",
"upFirstText": "První:",
"upNextText": "Další, ${COUNT}. hra bude:",
@ -1845,6 +1861,7 @@
"usingItunesTurnRepeatAndShuffleOnText": "Ujistěte se prosím, že je zaplý shuffle, a opakovat VŠE v iTunes,",
"v2AccountLinkingInfoText": "Pro propojení V2 účtů stiskněte tlačítko „Spravovat účet“",
"validatingTestBuildText": "Ověřuji testovací build...",
"viaText": "skrze",
"victoryText": "Vítězství!",
"voteDelayText": "Nelze spustit další hlas za ${NUMBER} sekund",
"voteInProgressText": "Hlasování již probíhá.",

View file

@ -25,10 +25,7 @@
"signInText": "Sign In",
"signInWithDeviceInfoText": "(an automatic account only available from this device)",
"signInWithDeviceText": "Sign in with device account",
"signInWithGameCircleText": "Sign in with Game Circle",
"signInWithGooglePlayText": "Sign in with Google Play",
"signInWithTestAccountInfoText": "(legacy account type; use device accounts going forward)",
"signInWithTestAccountText": "Sign in with test account",
"signInWithText": "Sign in with ${SERVICE}",
"signInWithV2InfoText": "(an account that works on all platforms)",
"signInWithV2Text": "Sign in with a BombSquad account",
"signOutText": "Sign Out",
@ -332,6 +329,8 @@
"getMoreGamesText": "Get More Games...",
"titleText": "Add Game"
},
"addToFavoritesText": "Add to Favorites",
"addedToFavoritesText": "Added '${NAME}' to Favorites.",
"allText": "All",
"allowText": "Allow",
"alreadySignedInText": "Your account is signed in from another device;\nplease switch accounts or close the game on your\nother devices and try again.",
@ -366,6 +365,7 @@
"chatMutedText": "Chat Muted",
"chatUnMuteText": "Unmute Chat",
"choosingPlayerText": "<choosing player>",
"codesExplainText": "Codes are provided by the developer to\ndiagnose and correct account issues.",
"completeThisLevelToProceedText": "You must complete\nthis level to proceed!",
"completionBonusText": "Completion Bonus",
"configControllersWindow": {
@ -446,6 +446,7 @@
"swipeText": "swipe",
"titleText": "Configure Touchscreen"
},
"configureDeviceInSystemSettingsText": "${DEVICE} can be configured in the System Settings app.",
"configureItNowText": "Configure it now?",
"configureText": "Configure",
"connectMobileDevicesWindow": {
@ -560,6 +561,8 @@
"disableXInputDescriptionText": "Allows more than 4 controllers but may not work as well.",
"disableXInputText": "Disable XInput",
"disabledText": "Disabled",
"discordFriendsText": "Want to look for new people to play with?\nJoin our Discord and find new friends!",
"discordJoinText": "Join the Discord",
"doneText": "Done",
"drawText": "Draw",
"duplicateText": "Duplicate",
@ -661,8 +664,6 @@
"flawlessWaveText": "Flawless Wave!",
"fourKillText": "QUAD KILL!!!",
"friendScoresUnavailableText": "Friend scores unavailable.",
"gameCenterText": "GameCenter",
"gameCircleText": "GameCircle",
"gameLeadersText": "Game ${COUNT} Leaders",
"gameListWindow": {
"cantDeleteDefaultText": "You can't delete the default playlist.",
@ -745,11 +746,11 @@
"manualYourLocalAddressText": "Your local address:",
"nearbyText": "Nearby",
"noConnectionText": "<no connection>",
"noPartiesAddedText": "No Parties Added",
"otherVersionsText": "(other versions)",
"partyCodeText": "Party Code",
"partyInviteAcceptText": "Accept",
"partyInviteDeclineText": "Decline",
"partyInviteGooglePlayExtraText": "(see the 'Google Play' tab in the 'Gather' window)",
"partyInviteIgnoreText": "Ignore",
"partyInviteText": "${NAME} has invited\nyou to join their party!",
"partyNameText": "Party Name",
@ -782,7 +783,6 @@
"wifiDirectOpenWiFiSettingsText": "Open Wi-Fi Settings",
"wifiDirectText": "Wi-Fi Direct",
"worksBetweenAllPlatformsText": "(works between all platforms)",
"worksWithGooglePlayDevicesText": "(works with devices running the Google Play (android) version of the game)",
"youHaveBeenSentAPromoCodeText": "You have been sent a ${APP_NAME} promo code:"
},
"getTicketsWindow": {
@ -808,7 +808,6 @@
"youHaveShortText": "you have ${COUNT}",
"youHaveText": "you have ${COUNT} tickets"
},
"googleMultiplayerDiscontinuedText": "Sorry, Googles 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.",
"googlePlayServicesNotAvailableText": "Google Play Services is not available.\nSome app functionality may be disabled.",
"googlePlayText": "Google Play",
@ -816,10 +815,12 @@
"alwaysText": "Always",
"fullScreenCmdText": "Fullscreen (Cmd-F)",
"fullScreenCtrlText": "Fullscreen (Ctrl-F)",
"fullScreenText": "Fullscreen",
"gammaText": "Gamma",
"highText": "High",
"higherText": "Higher",
"lowText": "Low",
"maxFPSText": "Max FPS",
"mediumText": "Medium",
"neverText": "Never",
"resolutionText": "Resolution",
@ -1065,7 +1066,9 @@
"noContinuesText": "(no continues)",
"noExternalStorageErrorText": "No external storage found on this device",
"noGameCircleText": "Error: not logged into GameCircle",
"noPluginsInstalledText": "No Plugins Installed",
"noScoresYetText": "No scores yet.",
"noServersFoundText": "No servers found.",
"noThanksText": "No Thanks",
"noTournamentsInTestBuildText": "WARNING: Tournament scores from this test build will be ignored.",
"noValidMapsErrorText": "No valid maps found for this game type.",
@ -1274,6 +1277,7 @@
"netTestingText": "Network Testing",
"resetText": "Reset",
"showBombTrajectoriesText": "Show Bomb Trajectories",
"showDevConsoleButtonText": "Show Dev Console Button",
"showInGamePingText": "Show In-Game Ping",
"showPlayerNamesText": "Show Player Names",
"showUserModsText": "Show Mods Folder",
@ -1290,7 +1294,6 @@
"sharingText": "Sharing...",
"showText": "Show",
"signInForPromoCodeText": "You must sign in to an account for codes to take effect.",
"signInWithGameCenterText": "To use a Game Center account,\nsign in with the Game Center app.",
"singleGamePlaylistNameText": "Just ${GAME}",
"singlePlayerCountText": "1 player",
"soloNameFilterText": "Solo ${NAME}",
@ -1365,6 +1368,8 @@
"storeText": "Store",
"submitText": "Submit",
"submittingPromoCodeText": "Submitting Code...",
"successText": "Success!",
"supportEmailText": "If you are experiencing any problems with the\napp, please email ${EMAIL}.",
"teamNamesColorText": "Team Names/Colors...",
"telnetAccessGrantedText": "Telnet access enabled.",
"telnetAccessText": "Telnet access detected; allow?",
@ -1818,6 +1823,7 @@
"unlockThisInTheStoreText": "This must be unlocked in the store.",
"unlockThisProfilesText": "To create more than ${NUM} profiles, you need:",
"unlockThisText": "To unlock this, you need:",
"unsupportedControllerText": "Sorry, controller \"${NAME}\" is not supported.",
"unsupportedHardwareText": "Sorry, this hardware is not supported by this build of the game.",
"upFirstText": "Up first:",
"upNextText": "Up next in game ${COUNT}:",
@ -1829,6 +1835,7 @@
"usingItunesText": "Using Music App for soundtrack...",
"v2AccountLinkingInfoText": "To link V2 accounts, use the 'Manage Account' button.",
"validatingTestBuildText": "Validating Test Build...",
"viaText": "via",
"victoryText": "Victory!",
"voteDelayText": "You can't start another vote for ${NUMBER} seconds",
"voteInProgressText": "A vote is already in progress.",

View file

@ -1,76 +1,77 @@
{
"accountSettingsWindow": {
"accountNameRules": "Marapat na ang pangalan ng account na iyon ay walang mga special characters o mga emoji",
"accountsText": "Mga Account",
"accountNameRules": "Hindi pwede ang pangalan na may emoji o mga ibang special characters",
"accountsText": "Mga Manlalaro",
"achievementProgressText": "Mga Nakamtan: ${COUNT} sa ${TOTAL}",
"campaignProgressText": "Ang Progreso sa Laro [Mahirap]: ${PROGRESS}",
"changeOncePerSeason": "Mapapalit mo lang ito isa-isa kada season",
"changeOncePerSeasonError": "Kailangan mo muna maghintay ng susunod na season para mapalitan ito. (${NUM} araw)",
"customName": "Custom na Pangalan",
"googlePlayGamesAccountSwitchText": "Kung gusto mong gamitin ang iba ninyong Google Account,\nGumamit ka ng Google Play Games app upang maipalit.",
"linkAccountsEnterCodeText": "Ilagay ang Code",
"linkAccountsGenerateCodeText": "Gumawa ng Code",
"linkAccountsInfoText": "(ibahagi ang pag-usad sa iba't ibang platform)",
"linkAccountsInstructionsNewText": "Para maiugnay ang dalawang accounts, gumawa ka ng code sa una at ilagay \nyung code sa pangalawa. Data na galing sa pangalawang account ay \nmaibabahagi sa dalawa.\n(Data na nasa unang account ay mawawala)\n\nMaari kang magugnay ng hangang ${COUNT} accounts.\n\nIMPORTANTE: Iugnay lamang ang iyong mga accounts, \ndahil kapag iuugnay mo sa kaibigan mo ang iyong \naccount,hindi kayo makakapaglaro ng sabay.",
"campaignProgressText": "Ang Progreso sa Campgain [Mahirap]: ${PROGRESS}",
"changeOncePerSeason": "Mapapalit mo lang ito isang beses kada season",
"changeOncePerSeasonError": "Kailangan mo muna maghintay ng susunod na panahon para mapalitan ito. (${NUM} araw)",
"customName": "Kahit-anong Pangalan",
"googlePlayGamesAccountSwitchText": "Kung gusto mong gamitin ang iba ninyong Google Account, \nkailangan mo gamitin ang Google Play Games app upang maipalit ito.",
"linkAccountsEnterCodeText": "Ilagay ang Kowd",
"linkAccountsGenerateCodeText": "Gumawa ng Kowd",
"linkAccountsInfoText": "(ibahagi ang pag-usad sa ibang mga platform)",
"linkAccountsInstructionsNewText": "Para maiugnay ang dalawang accounts, gumawa ka ng kowd sa una at ilagay \nyung kowd sa pangalawa. Data na galing sa pangalawang account ay \nmaibabahagi sa dalawa.\n(Data na nasa unang account ay mawawala)\n\nMaari kang mag link ng hangang ${COUNT} accounts.\n\nIMPORTANTE: Iugnay lamang ang iyong mga accounts, \ndahil kapag iuugnay mo sa kaibigan mo ang iyong \naccount,hindi kayo makakapaglaro ng sabay.",
"linkAccountsInstructionsText": "Para mag-ugnay ng dalawang account, gumawa ng code\nsa isa at ilagay ang code na iyon sa kabila.\nAng iyong pag-usad at imbentaryo ay pagsasamahin.\nMaaari mong i-ugnay hanggang sa ${COUNT} accounts.\n\nBabala lang; hindi na ito maibabalik!",
"linkAccountsText": "Iugnay ang mga Account",
"linkedAccountsText": "Naka-ugnay na mga Account",
"manageAccountText": "I-Manage ang Account",
"nameChangeConfirm": "Baguhin ang pangalan ng iyong account sa ${NAME}?",
"resetProgressConfirmNoAchievementsText": "Ibabalik nito sa dati ang iyong pag-usad,\nat lokal na mga high-score (pwera sa ticket).\nHindi na ito maibabalik pa. Ipagpatuloy pa rin?",
"resetProgressConfirmText": "Ibabalik nito sa dati ang iyong pag-usad,\nmga nakamtan, at lokal na mga high-score\n(pwera sa ticket). Hindi na ito maibabalik\npa. Ipagpatuloy pa rin?",
"linkAccountsText": "Ilink ang mga Account",
"linkedAccountsText": "Naka-link na mga Account",
"manageAccountText": "I-Pamahalaan ang Account",
"nameChangeConfirm": "Ipalitan ang pangalan ng iyong account sa ${NAME}?",
"resetProgressConfirmNoAchievementsText": "Ibabalik nito sa dati ang iyong pag-usad,\nat lokal na mga high-score (pwera sa mga ticket).\nHindi na ito maibabalik. Ipagpatuloy pa rin?",
"resetProgressConfirmText": "Ibabalik nito sa dati ang iyong pag-usad,\nmga nakamtan, at lokal na mga high-score\n(pwera sa mga ticket). Hindi na ito maibabalik\nulit. Ipagpatuloy pa rin?",
"resetProgressText": "I-reset ang Progreso",
"setAccountName": "I-set ang Account name",
"setAccountName": "I-set ang pangngalan ng Account",
"setAccountNameDesc": "Piliin ang pangalan na ipapakita para sa iyong account.\nMaaari mong gamitin ang pangalan mula sa isa sa iyong mga naka-link \nna account o lumikha ng isang natatanging pasadyang pangalan.",
"signInInfoText": "Magsign-in para kumolekta ng mga ticket, makipagkompetensya online,\nat makabahagi ng pag-usad sa iba't ibang mga device.",
"signInText": "Mag-sign in",
"signInWithDeviceInfoText": "(isang automatic account na magagamit lamang sa device na ito)",
"signInWithDeviceText": "Mag-sign in gamit ang device",
"signInWithGameCircleText": "Magsign-in gamit ang Game Circle",
"signInWithGooglePlayText": "Magsign-in gamit ang Google Play",
"signInInfoText": "Pumasok o gumawa nang account para kumolekta ng mga ticket, makipagkompetensya online,\nat makabahagi ng pag-usad sa iba't ibang mga device.",
"signInText": "Pumasok sa account",
"signInWithDeviceInfoText": "(automatic account na magagamit lamang sa device na ito)",
"signInWithDeviceText": "Pumasok gamit ang device account",
"signInWithGameCircleText": "Pumasok sa account gamit ang Game Circle",
"signInWithGooglePlayText": "Pumasok sa account gamit ang Google Play",
"signInWithTestAccountInfoText": "(uri ng legacy account; gamitin ang mga account ng device na pasulong)",
"signInWithTestAccountText": "Magsign in gamit ang test account",
"signInWithV2InfoText": "(ang account na gumagana sa lahat na platforms)",
"signInWithV2Text": "Mag sign in gamit ang BombSquad account",
"signOutText": "Mag-sign out",
"signingInText": "Nagsasign-in...",
"signingOutText": "Nagsasign-out...",
"signInWithTestAccountText": "Pumasok gamit ang test account",
"signInWithText": "Mag sign in gamit ang ${SERVICE}",
"signInWithV2InfoText": "(ang account na gumagana sa lahat ng platforms)",
"signInWithV2Text": "Pumasok gamit ang BombSquad account",
"signOutText": "Umalis",
"signingInText": "Pumapasok sa account...",
"signingOutText": "Umaalis sa account...",
"ticketsText": "Mga ticket: ${COUNT}",
"titleText": "Account",
"unlinkAccountsInstructionsText": "Pumili ng account na i-uunlink",
"unlinkAccountsText": "I-unlink ang mga accounts",
"unlinkLegacyV1AccountsText": "I-unlink ang mga Legacy (V1) Account",
"v2LinkInstructionsText": "Gamitin ang link na ito para gumawa ng account o mag sign in.",
"viaAccount": "(sa pamamagitan ng account ${NAME})",
"youAreSignedInAsText": "Nakasign-in ka bilang:"
"titleText": "Manlalaro",
"unlinkAccountsInstructionsText": "Pumili ng manlalaro na i-uunlink",
"unlinkAccountsText": "I-unlink ang mga manlalaro",
"unlinkLegacyV1AccountsText": "I-unlink ang mga Legacy (V1) na mga Account",
"v2LinkInstructionsText": "Gamitin ang link na ito para gumawa ng account o pumasok sa account.",
"viaAccount": "(sa pamamagitan ng manlalaro ${NAME})",
"youAreSignedInAsText": "Nakasign-in ka bilang si:"
},
"achievementChallengesText": "Mga nakamit",
"achievementChallengesText": "Mga nakamit na",
"achievementText": "Mga Nakamtan",
"achievements": {
"Boom Goes the Dynamite": {
"description": "Mapasabog ang 3 kalaban gamit ang TNT",
"descriptionComplete": "Napasabog ang 3 kalaban gamit ang TNT",
"descriptionFull": "Mapasabog ang 3 kalaban gamit ang TNT sa ${LEVEL}",
"description": "Magpasabog nang TNT para mamatay ang 3 na salbahe",
"descriptionComplete": "Napasabog ang 3 salbahe gamit ang TNT",
"descriptionFull": "Ipasabog and 3 salbahe gamit ang TNT ${LEVEL}",
"descriptionFullComplete": "Napasabog ang 3 kalaban gamit ang TNT sa ${LEVEL}",
"name": "Sabog ang Sabi ng Dinamita"
},
"Boxer": {
"description": "Manalo sa laro ng hindi gumagamit ng bomba",
"descriptionComplete": "Nanalo sa laro ng hindi gumagamit ng bomba",
"descriptionFull": "Tapusin ang ${LEVEL} na walang gamit na bomba",
"descriptionFullComplete": "Natapos ang ${LEVEL} na himdi gumagamit ng bomba",
"description": "Manalo sa laro ng hindi gumagamit ng mga bomba",
"descriptionComplete": "Manalo sa laro ng hindi gumagamit ng bomba",
"descriptionFull": "Tapusin ang ${LEVEL} habang hindi gumagamit nang bomba",
"descriptionFullComplete": "Natapos ang ${LEVEL} habang hindi gumagamit nang bomba",
"name": "Boksingero"
},
"Dual Wielding": {
"descriptionFull": "Ikonekta ang 2 controllers (hardware o app)",
"descriptionFullComplete": "Konektado ang 2 controllers (hardware o app)",
"name": "Dalawang Nangalaro"
"descriptionFull": "Ikonekta ang dalawang mga controllers (hardware o app)",
"descriptionFullComplete": "Nakonektado na ang 2 controllers (hardware o app)",
"name": "Dalawang Manlalaro"
},
"Flawless Victory": {
"description": "Manalo nang hindi natatamaan",
"descriptionComplete": "Nanalo nang hindi natamaan",
"descriptionFull": "Manalo sa ${LEVEL} nang hindi makakakuha ng hit",
"descriptionFullComplete": "Nanalo sa ${LEVEL} nang hindi nakakakuha ng hit",
"description": "Manalo nang hindi natatamaan ng kalaban",
"descriptionComplete": "Nanalo nang hindi natamaan ng kalaban",
"descriptionFull": "Manalo sa ${LEVEL} nang hindi matatamaan",
"descriptionFullComplete": "Nanalo sa ${LEVEL} nang hindi natatamaan",
"name": "Di Mintis Na Pagtagumpay"
},
"Free Loader": {
@ -283,7 +284,7 @@
"name": "Manlalaro Ng Koponan"
},
"The Great Wall": {
"description": "Itigil ang bawat kalaban",
"description": "Patayin ang lahat ng salbahe",
"descriptionComplete": "Pinigilan ang bawat kalaban",
"descriptionFull": "Itigil ang bawat kalaban sa ${LEVEL}",
"descriptionFullComplete": "Pinigilan ang bawat kalaban sa ${LEVEL}",
@ -363,10 +364,11 @@
"cancelText": "Kanselahin",
"cantConfigureDeviceText": "Pasensya na, ang ${DEVICE} na ito ay hindi ma-configure.",
"challengeEndedText": "Natapos na ang challenge na ito.",
"chatMuteText": "I-mute ang Chat",
"chatMuteText": "Tahimikin Ang Chat Mo",
"chatMutedText": "Na-mute ang Chat",
"chatUnMuteText": "I-unmute ang Chat",
"choosingPlayerText": "<pumipili ng manlalaro>",
"codesExplainText": "Binigay ng developer ang mga codes \npara i-diagnose at i-tama ang mga issues sa account.",
"completeThisLevelToProceedText": "I complete mo muna\nang level na ito bago ka mag-proceed!",
"completionBonusText": "Bonus sa Pagkumpleto nito:",
"configControllersWindow": {
@ -386,16 +388,16 @@
"titleText": "I-configure ang mga Controller"
},
"configGamepadWindow": {
"advancedText": "Advanced",
"advancedTitleText": "Advanced na Setup ng Controller",
"advancedText": "Mga Iba Pa",
"advancedTitleText": "Iba Pang Setup ng Controller",
"analogStickDeadZoneDescriptionText": "(itaas ito kapag ang iyong karakter ay nag d-drift kapag binitawan mo ang stick)",
"analogStickDeadZoneText": "Analog Stick Dead Zone",
"appliesToAllText": "(nalalapat sa lahat ng controller ng ganitong uri)",
"autoRecalibrateDescriptionText": "(paganahin ito kung ang iyong karakter ay hindi gumagalaw ng buong bilis)",
"autoRecalibrateText": "Auto-Recalibrate Analog Stick",
"axisText": "aksis",
"clearText": "alisin",
"dpadText": "dpad",
"clearText": "i-bura",
"dpadText": "DPAD",
"extraStartButtonText": "Extra na Start Button",
"ifNothingHappensTryAnalogText": "Kapag walang gumagana, i-try na i-assign sa analog stick.",
"ifNothingHappensTryDpadText": "Kapag hindi gumana, i-try na i-assign sa d-pad.",
@ -447,11 +449,13 @@
"swipeText": "mag-swipe",
"titleText": "I-configure ang Touchscreen"
},
"configureDeviceInSystemSettingsText": "Ang ${DEVICE} ay pwede ma-configure sa System Settings app.",
"configureItNowText": "I-configure ngayon?",
"configureText": "Configure",
"connectMobileDevicesWindow": {
"amazonText": "Amazon Appstore",
"appStoreText": "App Store",
"bestResultsScale": 0.6,
"bestResultsText": "Para sa pinakamahusay na mga resulta, kakailanganin mo ng isang lag-free na wifi network. Kaya mo\nbawasan ang wifi lag sa pamamagitan ng pag-off ng iba pang mga wireless na device, sa pamamagitan ng\nnaglalaro malapit sa iyong wifi router, at sa pamamagitan ng pagkonekta sa\ndirektang host ng laro sa network sa pamamagitan ng ethernet.",
"explanationText": "Para gumamit ng smart-phone o tablet bilang wireless controller,\ni-install ang \"${REMOTE_APP_NAME}\" na app dito. Anumang bilang ng mga device\nmaaaring kumonekta sa isang larong ${APP_NAME} sa Wi-Fi, at libre ito!",
"forAndroidText": "para sa Andriod:",
@ -495,7 +499,7 @@
"skipWaitText": "Lagktawang Paghintay",
"timeRemainingText": "Natitirang Oras",
"toRankedText": "Sagad Sa Ranggo",
"totalText": "kabuuan",
"totalText": "kabuuhan",
"tournamentInfoText": "Makipagkumpitensya para sa matataas na marka sa\nibang mga manlalaro sa iyong liga.\n\nAng mga premyo ay iginagawad sa pinakamataas na iskor\nmga manlalaro kapag nag-expire ang oras ng tournament.",
"welcome1Text": "Maligayang pagdating sa ${LEAGUE}. Maaari mong pagbutihin ang iyong\nranggo ng liga sa pamamagitan ng pagkamit ng mga star rating, pagkumpleto\nmga tagumpay, at panalong tropeo sa mga paligsahan.",
"welcome2Text": "Maaari ka ring makakuha ng mga tiket mula sa marami sa parehong mga aktibidad.\nMaaaring gamitin ang mga tiket para i-unlock ang mga bagong character, mapa, at\nmini-games, para makapasok sa mga tournament, at higit pa.",
@ -541,7 +545,7 @@
"stressTestRoundDurationText": "Pagtagal Ng Round",
"stressTestTitleText": "Stress Test",
"titleText": "Benchmarks at Stress Test",
"totalReloadTimeText": "Kabuuang reload time: ${TIME} (tingnan Ang log para sa mga detalye)"
"totalReloadTimeText": "Kabuuhang reload time: ${TIME} (tingnan Ang log para sa mga detalye)"
},
"defaultGameListNameText": "Default ${PLAYMODE} Playlist",
"defaultNewGameListNameText": "Ang aking ${PLAYMODE} Playlist",
@ -560,9 +564,11 @@
"disableXInputDescriptionText": "Pumayag ng higit sa 4 na controllers ngunit maaaring hindi mabuti ang kalagay",
"disableXInputText": "Disable XInput",
"disabledText": "Naka-disabled",
"discordFriendsText": "Gusto mong may kalaro kang mga tao na gusto mo?\nSumali sa aming Discord server at hanapin mo ang kaibiganin mo!",
"discordJoinText": "Sumali sa Discord",
"doneText": "Tapos",
"drawText": "Patas",
"duplicateText": "I-duplicate",
"duplicateText": "Duplikaduhin",
"editGameListWindow": {
"addGameText": "Idagdag na\nLaro",
"cantOverwriteDefaultText": "Hindi ma-overwrite ang default playlist!",
@ -687,16 +693,16 @@
"aboutText": "Tungkulin",
"addressFetchErrorText": "<error sa pagkuha ng mga address>",
"appInviteMessageText": "Pinadalhan ka ni ${NAME} ng ${COUNT} ticket sa ${APP_NAME}",
"appInviteSendACodeText": "Mag-send ka sa Kanila ng Code",
"appInviteSendACodeText": "Mag-Sent Ka Ng Kowd Sa Kanila",
"appInviteTitleText": "${APP_NAME} App Invite",
"bluetoothAndroidSupportText": "(gumagana sa anumang Android device na mayroong Bluetooth)",
"bluetoothDescriptionText": "Mag-host/sumali sa isang party sa pamamagitan ng Bluetooth:",
"bluetoothHostText": "Mag-host gamit ang Bluetooth",
"bluetoothJoinText": "Sumali gamit ang Bluetooth",
"bluetoothText": "Bluetooth",
"checkingText": "nag-checking…",
"copyCodeConfirmText": "Nakopya ang code sa clipboard.",
"copyCodeText": "I-kopya ang Code",
"checkingText": "sinusuri...",
"copyCodeConfirmText": "Nakopya na ang kowd sa clipboard.",
"copyCodeText": "Kopyahin ang kowd",
"dedicatedServerInfoText": "Para sa pinakamahusay na mga resulta, mag-set up ng nakalaang server. Tingnan ang bombsquadgame.com/server para malaman kung paano.",
"disconnectClientsText": "Ididiskonekta nito ang ${COUNT} (mga) manlalaro\nsa iyong party. Sigurado ka ba?",
"earnTicketsForRecommendingAmountText": "Makakatanggap ang mga kaibigan ng ${COUNT} na tiket kung susubukan nila ang laro\n(at makakatanggap ka ng ${YOU_COUNT} para sa bawat gagawa)",
@ -709,12 +715,12 @@
"freeCloudServerNotAvailableText": "Walang available na libreng cloud server.",
"friendHasSentPromoCodeText": "${COUNT} ${APP_NAME} na mga tiket mula sa ${NAME}",
"friendPromoCodeAwardText": "Makakatanggap ka ng ${COUNT} na tiket sa tuwing ito ay gagamitin.",
"friendPromoCodeExpireText": "Mag-e-expire ang code sa loob ng ${EXPIRE_HOURS} na oras at gagana lang para sa mga bagong manlalaro.",
"friendPromoCodeInstructionsText": "Upang gamitin ito, buksan ang ${APP_NAME} at pumunta sa \"Mga Setting->Advanced->Ilagay ang Code\".\nTingnan ang bombsquadgame.com para sa mga link sa pag-download para sa lahat ng sinusuportahang platform.",
"friendPromoCodeExpireText": "E-expire ang kowd sa loob ng ${EXPIRE_HOURS} na oras at gagana lang para sa mga bagong manlalaro.",
"friendPromoCodeInstructionsText": "Upang gamitin ito, buksan ang ${APP_NAME} at pumunta sa \"Mga Setting->Mga Iba Pa->Ilagay ang Kowd\".\nTingnan ang bombsquadgame.com para sa mga link sa pag-download para sa lahat ng sinusuportahang platform.",
"friendPromoCodeRedeemLongText": "Maaari itong ma-redem ng ${COUNT} na libreng tiket ng hanggang ${MAX_USES} na tao.",
"friendPromoCodeRedeemShortText": "Maaari itong ma-redem ng ${COUNT} na tiket sa larong ito.",
"friendPromoCodeWhereToEnterText": "(sa \"Settings->Advanced->Ilagay Ang Code\")",
"getFriendInviteCodeText": "Kumuha ng imbitasyon ng code ng kaibigan",
"friendPromoCodeWhereToEnterText": "(sa \"Settings->Mga Iba Pa->Ilagay Ang Kowd\")",
"getFriendInviteCodeText": "Kumuha ng imbitasyon ng kowd ng kaibigan",
"googlePlayDescriptionText": "Mag-imbita ng mga manlalaro ng Google Play sa iyong party:",
"googlePlayInviteText": "Mag-imbita",
"googlePlayReInviteText": "Mayroong ${COUNT} (mga) Google Play na manlalaro sa iyong party \nna madidiskonekta kung magsisimula ka ng bagong imbitasyon.\nIsama sila sa bagong imbitasyon para maibalik mo sila.",
@ -746,11 +752,11 @@
"nearbyText": "Malapit",
"noConnectionText": "<walang koneksyon>",
"otherVersionsText": "<iba pang mga bersyon>",
"partyCodeText": "Code ng Partido",
"partyCodeText": "Kowd ng Partido",
"partyInviteAcceptText": "Tanggapin",
"partyInviteDeclineText": "Tanggihan",
"partyInviteGooglePlayExtraText": "(tingnan ang 'Google Play' tab sa 'Sumama' window)",
"partyInviteIgnoreText": "Ignorahin",
"partyInviteIgnoreText": "Pabayaan",
"partyInviteText": "Inimbitahan ka ni ${NAME} \nna sumali sa kanilang party",
"partyNameText": "Pangalan Ng Partido",
"partyServerRunningText": "Tumatakbo ang iyong party server.",
@ -768,7 +774,7 @@
"privateText": "Pribado",
"publicHostRouterConfigText": "Maaaring mangailangan nito ng pag-configure ng port-forwarding sa iyong router. Para sa mas madaling opsyon, mag-host ng pribadong party.",
"publicText": "Publiko",
"requestingAPromoCodeText": "Humihiling ng code...",
"requestingAPromoCodeText": "Humihiling ng kowd...",
"sendDirectInvitesText": "I-send ng direktang imbitasyon",
"shareThisCodeWithFriendsText": "Ibahagi ang code na ito sa iyong mga kaibigan:",
"showMyAddressText": "Ipakita Ang Address Ko",
@ -816,10 +822,12 @@
"alwaysText": "Palagi",
"fullScreenCmdText": "Fullscreen (Cmd-F)",
"fullScreenCtrlText": "Fullscreen (Ctrl-F)",
"fullScreenText": "Fullscreen",
"gammaText": "Gama",
"highText": "Mataas",
"higherText": "Napakataas",
"lowText": "Mababa",
"maxFPSText": "Pinakamataas na FPS",
"mediumText": "Katamtaman",
"neverText": "Wala",
"resolutionText": "Resolusyon",
@ -857,22 +865,23 @@
"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",
"powerupLandMinesDescriptionText": "Ang mga ito ay dumating sa mga pakete ng 3;\nKapaki-pakinabang para sa base defense o\npaghinto ng mabilis na mga kalaban.",
"powerupImpactBombsNameText": "Bombang-Gatilyo",
"powerupLandMinesDescriptionText": "Ang mga ito ay dumating sa mga pakete ng 3;\nKapaki-pakinabang para sa base defense o\npaghinto ng mga mabibilis na kalaban.",
"powerupLandMinesNameText": "Mina",
"powerupPunchDescriptionText": "Ang iyong mga suntok ay mas mahirap,\nmas mabilis, mas mahusay, at mas malakas.",
"powerupPunchNameText": "Boxing-Gloves",
"powerupShieldDescriptionText": "Pumigil na pagsakit\nkaya hindi mo kailangan.",
"powerupShieldNameText": "Enrhiyang-Kalasag",
"powerupStickyBombsDescriptionText": "Dumikit sa anumang matamaan nila.\nItoy naging pagtawanan.",
"powerupStickyBombsNameText": "Malagkit-Bomba",
"powerupsSubtitleText": "Siyempre, walang larong kumpleto pag walang powerups:",
"powerupStickyBombsNameText": "Bombang-Malagkit",
"powerupsSubtitleText": "Siyempre, 'di kumpleto ang laro kapag walang mga powerups:",
"powerupsText": "Powerups",
"punchInfoText": "- Suntok -\nAng mga suntok ay mas nakakasakit\nmas mabilis ang paggalaw ng iyong mga kamay, kaya\ntumakbo at umiikot na parang baliw.",
"runInfoText": "- Takbo -\nPindutin ang ANY button para tumakbo. Ang mga trigger o mga button sa balikat ay gumagana nang maayos kung mayroon ka ng mga ito.\nAng pagtakbo ay nagpapabilis sa iyo ng mga lugar ngunit nahihirapan kang lumiko, kaya mag-ingat sa mga bangin.",
"punchInfoTextScale": 0.4,
"runInfoText": "- Takbo -\nPindutin ang KAHIT ANUMANG button para tumakbo. Ang mga trigger o mga gilid na button ay gumagana nang maayos kung mayroon ka ng mga ito.\nAng pagtakbo ay nagpapabilis sa iyo ng mga lugar ngunit nahihirapan kang lumiko, kaya mag-ingat sa mga bangin.",
"someDaysText": "May mga araw na parang gusto mong sumuntok ng kung ano. O nagpapasabog ng isang bagay.",
"titleText": "Tulong ng ${APP_NAME}",
"toGetTheMostText": "Upang masulit ang larong ito, kakailanganin mo:",
"toGetTheMostText": "Upang masulit ang larong ito, kakailanganin mo ng:",
"welcomeText": "Maligayang Pagdating sa ${APP_NAME}"
},
"holdAnyButtonText": "<hawakan ang anumang pindutan>",
@ -961,7 +970,7 @@
"kickVoteText": "Bumoto sa Pagki-kick",
"kickVotingDisabledText": "Naka-disable ang kick voting.",
"kickWithChatText": "I-type ang ${YES} sa chat para sa oo at ${NO} para sa hindi.",
"killsTallyText": "${COUNT} ang pinatay",
"killsTallyText": "${COUNT} pinatay",
"killsText": "Pinatay",
"kioskWindow": {
"easyText": "Madali",
@ -1022,7 +1031,7 @@
"resumeText": "Ipatuloy",
"settingsText": "Mga Setting"
},
"makeItSoText": "Gawin itong Kaya",
"makeItSoText": "Gawin mo syang parag ganyan",
"mapSelectGetMoreMapsText": "Kumuha ng Higit pang Mapa...",
"mapSelectText": "Pumili…",
"mapSelectTitleText": "Mapa ng ${GAME}",
@ -1041,9 +1050,9 @@
"multiKillText": "${COUNT}-PAGPATAY!!!",
"multiPlayerCountText": "${COUNT} na manlalaro",
"mustInviteFriendsText": "Tandaan: dapat kang mag-imbita ng mga kaibigan\nang panel na \"${GATHER}\" o i-attach\nmga controller para maglaro ng multiplayer.",
"nameBetrayedText": "${VICTIM} ay pinagtaksilan ni ${NAME}.",
"nameBetrayedText": "Pinagtaksilan ni ${NAME} si ${VICTIM}",
"nameDiedText": "${NAME} ay namatay.",
"nameKilledText": "${VICTIM} ay pinatay ni ${NAME}.",
"nameKilledText": "Pinatay ni ${NAME} si ${VICTIM}",
"nameNotEmptyText": "Hindi pwede ang walang pangalan!",
"nameScoresText": "${NAME} Naka-score!",
"nameSuicideKidFriendlyText": "Hindi sinasadyang namatay si ${NAME}.",
@ -1061,6 +1070,7 @@
"noExternalStorageErrorText": "Walang nakitang external na storage sa device na ito",
"noGameCircleText": "Error: hindi naka-log in sa GameCircle",
"noScoresYetText": "Wala pang score.",
"noServersFoundText": "Walang nahanap na servers.",
"noThanksText": "Salamat Nalang",
"noTournamentsInTestBuildText": "BABALA: Babalewalain ang mga score sa tournament mula sa test build na ito.",
"noValidMapsErrorText": "Walang nakitang valid na mapa para sa ganitong uri ng laro.",
@ -1107,10 +1117,10 @@
"twoToEightPlayersText": "2-8 na manlalaro"
},
"playerCountAbbreviatedText": "${COUNT}p",
"playerDelayedJoinText": "Papasok si ${PLAYER} sa simula ng susunod na round.",
"playerDelayedJoinText": "Papasok si ${PLAYER} sa simula ng susunod na laro.",
"playerInfoText": "Impormasyon ng Manlalaro",
"playerLeftText": "Umalis si ${PLAYER} sa laro.",
"playerLimitReachedText": "Naabot na ang limitasyon ng manlalaro na ${COUNT}; hindi pinapayagan ang mga ibang sumali.",
"playerLimitReachedText": "Naabot na ang limitasyon ng manlalaro na ${COUNT}; hindi pinapayagan ang mga ibang manlalaro sumali.",
"playerProfilesWindow": {
"cantDeleteAccountProfileText": "Hindi mo matatanggal ang profile ng iyong account.",
"deleteButtonText": "Itangal ang\nProfile",
@ -1129,14 +1139,14 @@
"pleaseWaitText": "Hintay lang…",
"pluginClassLoadErrorText": "Error sa paglo-load ang '${PLUGIN}' na klaseng plugin : ${ERROR}",
"pluginInitErrorText": "Error sa pagsisimula ang '${PLUGIN}' na plugin: ${ERROR}",
"pluginSettingsText": "Settings ng mga Plugins",
"pluginSettingsText": "Settings ng mga Plugin",
"pluginsAutoEnableNewText": "Paganahin ang Bagong Plugins",
"pluginsDetectedText": "May nakitang bagong (mga) plugin. I-restart para i-activate ang mga ito, o i-configure ang mga ito sa mga setting.",
"pluginsDisableAllText": "Di-Paganahin ang mga Plugins",
"pluginsEnableAllText": "Paganahin Lahat ng mga Plugins",
"pluginsDisableAllText": "Salantahin ang mga Plugin",
"pluginsEnableAllText": "Paganahin Lahat ng mga Plugin",
"pluginsRemovedText": "Hindi na nahanapan ang ${NUM} ng (mga) plugin.",
"pluginsText": "Mga Plugin",
"practiceText": "Pagsasagawa",
"practiceText": "Sanayan",
"pressAnyButtonPlayAgainText": "Pindutin ang anumang button para maglaro muli...",
"pressAnyButtonText": "Pindutin ang anumang button para magpatuloy...",
"pressAnyButtonToJoinText": "pindutin ang anumang button para sumali...",
@ -1152,7 +1162,7 @@
"codeText": "Code",
"enterText": "I-enter"
},
"promoSubmitErrorText": "Error sa pagsusumite ng code; suriin ang iyong koneksyon ng internet",
"promoSubmitErrorText": "Error sa pagsusumite ng kowd; suriin ang iyong koneksyon sa internet",
"ps3ControllersWindow": {
"macInstructionsText": "I-off ang power sa likod ng iyong PS3, siguraduhin\nNaka-enable ang Bluetooth sa iyong Mac, pagkatapos ay ikonekta ang iyong controller\nsa iyong Mac sa pamamagitan ng USB cable upang ipares ang dalawa. Mula noon, ikaw\nmaaaring gamitin ang home button ng controller para ikonekta ito sa iyong Mac\nsa alinman sa wired (USB) o wireless (Bluetooth) mode.\n\nSa ilang mga Mac maaari kang ma-prompt para sa isang passcode kapag nagpapares.\nKung mangyari ito, tingnan ang sumusunod na tutorial o google para sa tulong.\n\n\n\n\nDapat lumabas sa device ang mga PS3 controller na nakakonekta nang wireless\nlistahan sa System Preferences->Bluetooth. Maaaring kailanganin mong alisin ang mga ito\nmula sa listahang iyon kapag gusto mong gamitin muli ang mga ito sa iyong PS3.\n\nTiyakin din na idiskonekta ang mga ito sa Bluetooth kapag hindi naka-in\ngamitin o ang kanilang mga baterya ay patuloy na mauubos.\n\nDapat hawakan ng Bluetooth ang hanggang 7 konektadong device,\nkahit na ang iyong mileage ay maaaring mag-iba.",
"ouyaInstructionsText": "Para gumamit ng PS3 controller sa iyong OUYA, ikonekta lang ito gamit ang USB cable\nisang beses upang ipares ito. Ang paggawa nito ay maaaring madiskonekta ang iyong iba pang mga controller, kaya\ndapat mong i-restart ang iyong OUYA at i-unplug ang USB cable.\n\nMula noon, magagamit mo na ang HOME button ng controller para\nikonekta ito nang wireless. Kapag tapos ka nang maglaro, pindutin nang matagal ang HOME button\npara sa 10 segundo upang i-off ang controller; kung hindi, maaari itong manatili sa\nat mga basurang baterya.",
@ -1207,24 +1217,24 @@
"renameText": "I-palitan",
"replayEndText": "Itigil Ang Replay",
"replayNameDefaultText": "Replay ng Huling Laro",
"replayReadErrorText": "Error sa pagbabasa ng replay file.",
"replayReadErrorText": "May kamalian sa pagbabasa ng replay file.",
"replayRenameWarningText": "Palitan ang pangalan ng \"${REPLAY}\" pagkatapos ng isang laro kung gusto mong panatilihin ito; kung hindi, ito ay mapapatungan.",
"replayVersionErrorText": "Pasensya na, ginawa ang replay na ito sa ibang paraang\nbersyon ng laro at hindi magagamit.",
"replayWatchText": "Panoorin ang replay",
"replayWriteErrorText": "Error sa pagsulat ng replay file.",
"replayWriteErrorText": "May kamalian sa pagsulat ng replay file.",
"replaysText": "Mga Replay",
"reportPlayerExplanationText": "Gamitin ang email na ito upang mag-ulat ng pagdaya, hindi naaangkop na pananalita, o iba pang masamang gawin.\nPakilarawan sa ibaba:",
"reportThisPlayerCheatingText": "Pagdaya",
"reportThisPlayerCheatingText": "Dumadaya",
"reportThisPlayerLanguageText": "Hindi Angkop na Salita",
"reportThisPlayerReasonText": "Ano ang gusto mong iulat?",
"reportThisPlayerText": "Iulat ang Manlalaro na Ito",
"requestingText": "Humihiling",
"restartText": "I-restart",
"retryText": "I-retry",
"requestingText": "Humihiling...",
"restartText": "Umulit",
"retryText": "Ulitin",
"revertText": "Ibalik",
"runText": "Takbo",
"runText": "Tumakbo",
"saveText": "I-save",
"scanScriptsErrorText": "(Mga) error sa pag-scan ng mga script; Tignan ang log para sa mga detalye.",
"scanScriptsErrorText": "(Mga) kamalian sa pag-scan ng mga script; Tignan ang log para sa mga detalye.",
"scanScriptsMultipleModulesNeedUpdatesText": "Kailangan maibago para sa API ${API} ang ${PATH} at mga ${NUM} na iba pang modules.",
"scanScriptsSingleModuleNeedsUpdatesText": "Kailangan maibago para sa api ${API} ang ${PATH}.",
"scoreChallengesText": "Mga Hamon sa Iskor",
@ -1236,14 +1246,14 @@
"secondsText": "Segundo"
},
"scoreWasText": "(ay nasa ${COUNT})",
"selectText": "Piliin",
"selectText": "Pilihin",
"seriesWinLine1PlayerText": "ANG NANALO SA",
"seriesWinLine1TeamText": "ANG NANALO SA",
"seriesWinLine1Text": "ANG NANALO SA",
"seriesWinLine2Text": "SERYE!",
"seriesWinLine2Text": "SERYENG NITO!",
"settingsWindow": {
"accountText": "Account",
"advancedText": "Advanced",
"advancedText": "Mga Iba Pa",
"audioText": "Audio",
"controllersText": "Mga Controller",
"graphicsText": "Grapika",
@ -1263,13 +1273,14 @@
"forTestingText": "Tandaan: ang mga value na ito ay para lamang sa pagsubok at mawawala kapag lumabas ang app.",
"helpTranslateText": "Ang mga pagsasalin na hindi Ingles ng ${APP_NAME} ay isang komunidad\nsuportadong pagsisikap. Kung gusto mong mag-ambag o magtama\nisang pagsasalin, sundan ang link sa ibaba. Salamat!",
"kickIdlePlayersText": "I-kick Ang Mga Idle na Manlalaro",
"kidFriendlyModeText": "Kid-Friendly Mode (binawasan ang karahasan, atbp)",
"kidFriendlyModeText": "Pambata na Mode (binawasan ang karahasan, atbp)",
"languageText": "Wika",
"moddingGuideText": "Gabay sa Modding",
"mustRestartText": "Dapat mong i-restart ang laro para magka-epekto ito.",
"netTestingText": "Pagsusuri ng Network",
"resetText": "I-reset",
"showBombTrajectoriesText": "Ipakita ang Mga Trajectory ng Bomba",
"showDevConsoleButtonText": "Ipakita ang Dev Console Button",
"showInGamePingText": "Ipakita ang In-Game Ping",
"showPlayerNamesText": "Ipakita ang Mga Pangalan ng Manlalaro",
"showUserModsText": "Ipakita ang Mods Folder",
@ -1294,7 +1305,7 @@
"CharSelect": "Pagpili ng Karakter",
"Chosen One": "Napili ng Isa",
"Epic": "Larong Epic na Mode",
"Epic Race": "Epic na Takbuan",
"Epic Race": "Epic na Takbuhan",
"FlagCatcher": "Kunin ang Bandila",
"Flying": "Masayang Isip",
"Football": "Rugbi",
@ -1305,7 +1316,7 @@
"Marching": "Bantayan",
"Menu": "Pangunahing Menu",
"Onslaught": "Pagsalakay",
"Race": "Takbuan",
"Race": "Takbuhan",
"Scary": "Hari Ng Burol",
"Scores": "Screen Ng Iskor",
"Survival": "Kaligtasan",
@ -1333,7 +1344,7 @@
"loadingText": "Saglit lang…",
"mapsText": "Mga Mapa",
"miniGamesText": "Mga MiniGames",
"oneTimeOnlyText": "(isang beses lamang)",
"oneTimeOnlyText": "(isang beses lang)",
"purchaseAlreadyInProgressText": "Ang isang nabilhin ng item na ito ay isinasagawa na.",
"purchaseConfirmText": "Ibili ang ${ITEM}?",
"purchaseNotValidError": "Hindi wasto ang nabilhin.\nMakipag-ugnayan kay ${EMAIL} kung ito ay isang error.",
@ -1361,6 +1372,8 @@
"storeText": "Tindahan",
"submitText": "Ipasa",
"submittingPromoCodeText": "Nagsusumite ng Code...",
"successText": "Wakas!",
"supportEmailText": "Pag may problema sa app, \npaki-email ang ${EMAIL}.",
"teamNamesColorText": "Mga Pangalan/Kulay ng Team…",
"telnetAccessGrantedText": "Pinagana ang pag-access sa Telnet..",
"telnetAccessText": "Natuklasan ang pag-access sa Telnet; payagan?",
@ -1370,7 +1383,7 @@
"testBuildValidatedText": "Na-validate ang Test Build; Tamasahin!",
"thankYouText": "Salamat sa iyong suporta! Tangkilikin ang laro!!",
"threeKillText": "TRIPLENG PAGPATAY!!",
"timeBonusText": "Bonus Ng Oras",
"timeBonusText": "Bonus sa Oras",
"timeElapsedText": "Oras Na Lumipas",
"timeExpiredText": "Nag-expire Na Ang Oras!",
"timeSuffixDaysText": "${COUNT}d",
@ -1380,7 +1393,7 @@
"tipText": "Tip",
"titleText": "BombSquad",
"titleVRText": "BombSquad VR",
"topFriendsText": "Pangunahing Kaibigan",
"topFriendsText": "Pinakamataas na Kaibigan",
"tournamentCheckingStateText": "Sinusuri ang estado ng paligsahan; pakihintay...",
"tournamentEndedText": "Natapos na ang paligsahan na ito. Magsisimula ng bago mamaya.",
"tournamentEntryText": "Pagpasok sa Paligsahan",
@ -1393,12 +1406,12 @@
"translations": {
"characterNames": {
"Agent Johnson": "Ahente Johnson",
"B-9000": "B-9000",
"B-9000": "Makina-9000",
"Bernard": "Oso",
"Bones": "Buto",
"Butch": "Bakero",
"Easter Bunny": "Kuneho",
"Flopsy": "Malambot",
"Flopsy": "Magalaw",
"Frosty": "Taong Niyebe",
"Gretel": "Mag-aawit Na Manananggal",
"Grumbledorf": "Manggagaway",
@ -1414,7 +1427,7 @@
"Sammy Slam": "Mambubuno",
"Santa Claus": "Santa Klaus",
"Snake Shadow": "Aninong Balatkayo",
"Spaz": "Kawal",
"Spaz": "Mandirigma",
"Taobao Mascot": "Taobao Maskot",
"Todd McBurton": "Todd McBurton",
"Zoe": "Dalagang Bombero",
@ -1430,7 +1443,7 @@
"Pro Football": "Batidong Rugbi",
"Pro Onslaught": "Batidong Pagsalakay",
"Pro Runaround": "Batidong Bantayan",
"Rookie ${GAME}": "Bagitong ${GAME}",
"Rookie ${GAME}": "Pang bago na ${GAME}",
"Rookie Football": "Bagitong Rugbi",
"Rookie Onslaught": "Bagitog Pagsalakay",
"The Last Stand": "Ang Huling Labanan",
@ -1446,7 +1459,7 @@
"Carry the flag for a set length of time.": "Hawakan ang bandila para sa isang nakatakdang haba ng oras.",
"Crush ${ARG1} of your enemies.": "Patayin ang ${ARG1} ng iyong mga kalaban",
"Defeat all enemies.": "Talunin ang lahat ng iyong mga kalaban",
"Dodge the falling bombs.": "Umiwas sa mga bumabagsak na bomba.",
"Dodge the falling bombs.": "Iwasan ang bumabagsak na bomba.",
"Final glorious epic slow motion battle to the death.": "Huling maluwalhating epic slow motion na labanan hanggang kamatayan.",
"Gather eggs!": "Ipunin ng mga itlog!",
"Get the flag to the enemy end zone.": "Kunin ang bandila sa end zone ng kalaban.",
@ -1461,7 +1474,7 @@
"Run ${ARG1} laps.": "Tumakbo ng ${ARG1} ikot",
"Run ${ARG1} laps. Your entire team has to finish.": "Tumakbo ng {ARG1} ikot. Kailangang matapos ang iyong buong team na ito.",
"Run 1 lap.": "Tumakbo ng 1 ikot.",
"Run 1 lap. Your entire team has to finish.": "Tumakbo ng 1 ikot. Kailangang matapos ang iyong buong team na ito.",
"Run 1 lap. Your entire team has to finish.": "Tumakbo ng 1 ikot. Kailangang matapos ang iyong buong grupo.",
"Run real fast!": "Tumakbo ng mabilis!",
"Score ${ARG1} goals.": "Makaiskor ng ${ARG1} gol.",
"Score ${ARG1} touchdowns.": "Makaiskor ng ${ARG1} touchdowns.",
@ -1480,7 +1493,7 @@
"carry the flag for ${ARG1} seconds": "Hawakan ang bandila ng ${ARG1} segundo",
"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",
"last team standing wins": "ang huling grupo ay mananalo",
"return ${ARG1} flags": "Magnakaw ng ${ARG1} na mga bandera",
"return 1 flag": "ibalik ang 1 bandila",
"run ${ARG1} laps": "Tumakbo ng ${ARG1} ikot",
@ -1495,14 +1508,14 @@
"touch 1 flag": "humawak ng 1 bandila"
},
"gameNames": {
"Assault": "Pag-atake",
"Assault": "Pag hawak ng bandila",
"Capture the Flag": "Kunin ang Bandila",
"Chosen One": "Napili ang Isa",
"Chosen One": "Napili na Isa",
"Conquest": "Pagsakop",
"Death Match": "Laban ng Kamatayan",
"Easter Egg Hunt": "Paghahanap ng mga Easter Egg",
"Elimination": "Kaligtasan",
"Football": "Rugbi",
"Elimination": "Pagbabawas sa away",
"Football": "Putbol",
"Hockey": "Hockey",
"Keep Away": "Layuan Mo",
"King of the Hill": "Hari ng Burol",
@ -1533,7 +1546,7 @@
"Finnish": "Finnish",
"French": "Pranses",
"German": "Aleman",
"Gibberish": "Walang Kwentang Linguahe",
"Gibberish": "Hindi Naiitindihan na Linguahe",
"Greek": "Griyego",
"Hindi": "Indiyano",
"Hungarian": "Hanggaryan",
@ -1571,7 +1584,7 @@
"Crag Castle": "Kastilyong Bangin",
"Doom Shroom": "Itim na Kabute",
"Football Stadium": "Istadyum",
"Happy Thoughts": "Masayang Isip",
"Happy Thoughts": "Masayan na mga Isip",
"Hockey Stadium": "Istadyum ng Hockey",
"Lake Frigid": "Yelong Lawa",
"Monkey Face": "Mukha ng Unggoy",
@ -1593,7 +1606,7 @@
"Score": "Iskor",
"Survived": "Nakaligtas",
"Time": "Oras",
"Time Held": "Oras na Gaganapin"
"Time Held": "Oras na Nahawak"
},
"serverResponses": {
"A code has already been used on this account.": "Nagamit na ang isang code sa account na ito.",
@ -1675,7 +1688,7 @@
"5 Minutes": "5 minuto",
"8 Seconds": "8 segundo",
"Allow Negative Scores": "Payagan ang Mga Negatibong Iskor",
"Balance Total Lives": "Balansehin ang Kabuuang Buhay",
"Balance Total Lives": "Balansehin ang Kabuuhang Buhay",
"Bomb Spawning": "Paglitaw ng Bomba",
"Chosen One Gets Gloves": "Ang Isa Sa Napili Ay Makukuha Ng Gloves",
"Chosen One Gets Shield": "Ang Isa Sa Napili Ay Makukuha Ng Kalasag",
@ -1814,6 +1827,7 @@
"unlockThisInTheStoreText": "Ito ay dapat na naka-unlock sa tindahan.",
"unlockThisProfilesText": "Upang lumikha ng higit sa ${NUM} na mga profile, kailangan mo:",
"unlockThisText": "Upang i-unlock ito, kailangan mo ng:",
"unsupportedControllerText": "Sorry, ang pangalan na \"${NAME}\" ay hindi pa supported.",
"unsupportedHardwareText": "Pasensya na, ang hardware na ito ay hindi suportado ng build na ito ng laro.",
"upFirstText": "Bumangon muna:",
"upNextText": "Susunod sa larong ${COUNT}:",
@ -1825,6 +1839,7 @@
"usingItunesText": "Paggamit ng Music App para sa soundtrack...",
"v2AccountLinkingInfoText": "Upang ma-link ang mga V2 account mo, dumeretso ka sa “I-Manage ang Account“.",
"validatingTestBuildText": "Pinapatunayan ang Test Build...",
"viaText": "via",
"victoryText": "Panalo!",
"voteDelayText": "Hindi ka makapagsimula ng bagong botohan sa ${NUMBER} segundo",
"voteInProgressText": "Ang pagboboto ay isinasagawa na.",
@ -1858,7 +1873,7 @@
"wellSureText": "Oo Syempre!",
"whatIsThisText": "Ano ito?",
"wiimoteLicenseWindow": {
"titleText": "Copyright ni DarwiinRemote"
"titleText": "Copyright ng DarwiinRemote"
},
"wiimoteListenWindow": {
"listeningText": "Nakikinig sa Wiimote...",

View file

@ -32,6 +32,7 @@
"signInWithGooglePlayText": "Connectez-vous avec Google Play",
"signInWithTestAccountInfoText": "(ancien compte; utilisez les comptes de cet appareil pour les prochaines fois)",
"signInWithTestAccountText": "Connectez-vous avec un compte test",
"signInWithText": "Connectez-vous avec ${SERVICE}",
"signInWithV2InfoText": "(un compte qui fonctionne sur toutes les plateformes)",
"signInWithV2Text": "Connectez-vous avec un compte Bombsquad",
"signOutText": "Se déconnecter",
@ -339,6 +340,7 @@
"getMoreGamesText": "Obtenir plus de jeux...",
"titleText": "Ajouter un Jeu"
},
"allText": "Tous",
"allowText": "Autoriser",
"alreadySignedInText": "Votre compte est connecté sur un autre appareil;\nveuillez changer de compte ou fermez le jeu sur \nles autres appareils et réessayez.",
"apiVersionErrorText": "Impossible de charger le jeu ${NAME}; sa version api est ${VERSION_USED}; nous demandons la version ${VERSION_REQUIRED}.",
@ -375,6 +377,7 @@
"chatMutedText": "Tchat muet",
"chatUnMuteText": "Réactiver tchat",
"choosingPlayerText": "<choix du joueur>",
"codesExplainText": "Les codes sont fournis par le développeur pour \ndiagnostiquer et corriger les problèmes de compte.",
"completeThisLevelToProceedText": "Vous devez compléter ce \nniveau pour continuer!",
"completionBonusText": "Bonus de fin",
"configControllersWindow": {
@ -458,6 +461,7 @@
"titleText": "Configurer l'Écran Tactile",
"touchControlsScaleText": "Taille des boutons tactiles"
},
"configureDeviceInSystemSettingsText": "${DEVICE} peut être configuré dans Paramètres Système.",
"configureItNowText": "Configurer maintenant?",
"configureText": "Configurer",
"connectMobileDevicesWindow": {
@ -578,6 +582,9 @@
"disableRemoteAppConnectionsText": "Désactiver les connexions d'applications-manettes",
"disableXInputDescriptionText": "Permet plus que 4 manettes mais risque de malfonctionner.",
"disableXInputText": "Désactiver XInput",
"disabledText": "Désactivé",
"discordFriendsText": "Vous voulez chercher de nouvelles personnes avec qui jouer ? \nRejoignez notre Discord et trouvez de nouveaux amis !",
"discordJoinText": "Rejoignez le Discord",
"doneText": "Terminé",
"drawText": "Égalité",
"duplicateText": "Dupliquer",
@ -651,6 +658,7 @@
"useMusicFolderText": "Dossier de Fichiers Musicaux"
},
"editText": "Éditer",
"enabledText": "Activé",
"endText": "Terminé",
"enjoyText": "Amusez-vous Bien!",
"epicDescriptionFilterText": "${DESCRIPTION} Dans un \"slow-motion\" épique.",
@ -854,10 +862,12 @@
"alwaysText": "Toujours",
"fullScreenCmdText": "Plein Écran (Cmd-F)",
"fullScreenCtrlText": "Plein Écran (Ctrl-F)",
"fullScreenText": "plein écran",
"gammaText": "Gamma",
"highText": "Élevé",
"higherText": "Très élevé",
"lowText": "Bas",
"maxFPSText": "FPS maximum",
"mediumText": "Moyen",
"neverText": "Jamais",
"resolutionText": "Résolution",
@ -1116,6 +1126,7 @@
"noJoinCoopMidwayText": "Vous ne pouvez pas rejoindre une partie co-cop en plein milieu.",
"noProfilesErrorText": "Vous avez aucun profil de joueur, vous êtes donc coincés avec '${NAME}'.\nAllez à Paramètres->Profils des Joueurs pour vous créer un profil.",
"noScoresYetText": "Aucun score pour le moment.",
"noServersFoundText": "Aucun serveur trouvé.",
"noThanksText": "Non Merci",
"noTournamentsInTestBuildText": "AVERTISSEMENT: les scores de tournoi de cette version de test seront ignorés.",
"noValidMapsErrorText": "Aucune carte valide a été trouvée pour ce type de jeu.",
@ -1290,6 +1301,8 @@
"runText": "Courir",
"saveText": "Sauvegarder",
"scanScriptsErrorText": "Erreur(s) dans les scripts. Consulter le journal pour plus de détails.",
"scanScriptsMultipleModulesNeedUpdatesText": "${PATH} et ${NUM} autre(s) module(s) doivent être mis à jour pour l'API ${API}.",
"scanScriptsSingleModuleNeedsUpdatesText": "${PATH} doit être mis à jour pour l'API ${API}.",
"scoreChallengesText": "Défis de Score",
"scoreListUnavailableText": "Liste des scores indisponible.",
"scoreText": "Score",
@ -1335,6 +1348,7 @@
"netTestingText": "Tester Votre Réseau",
"resetText": "Réinitialiser",
"showBombTrajectoriesText": "Montrer les trajectoires de bombe",
"showDevConsoleButtonText": "Afficher le Bouton de la Console de Développeur",
"showInGamePingText": "Afficher La Latence En Jeu",
"showPlayerNamesText": "Montrer les Noms des Joueurs",
"showUserModsText": "Montrer le Dossier des Mods",
@ -1430,6 +1444,8 @@
"storeText": "Magasin",
"submitText": "Soumettre",
"submittingPromoCodeText": "Envoi du code...",
"successText": "Succès!",
"supportEmailText": "Si vous rencontrez des problèmes avec \nl'application, veuillez envoyer un e-mail à ${EMAIL}.",
"teamNamesColorText": "Noms d'équipe/Couleurs...",
"teamsText": "Équipes",
"telnetAccessGrantedText": "L'accès Telnet est activé.",
@ -1911,6 +1927,7 @@
"unlockThisInTheStoreText": "Cela doit être débloqué dans le magasin.",
"unlockThisProfilesText": "Pour créer plus de ${NUM} profiles, vous avez besoin de:",
"unlockThisText": "Pour débloquer ceci, vous avez besoin:",
"unsupportedControllerText": "Désolé, contrôleur \"${NAME}\" pas pris en charge.",
"unsupportedHardwareText": "Désolé, ce hardware n'est pas supporté par cette version du jeu.",
"upFirstText": "En premier:",
"upNextText": "Le jeu ${COUNT} sera:",
@ -1924,6 +1941,7 @@
"v2AccountLinkingInfoText": "Pour lier des comptes V2, utilisez le bouton 'Gérer compte'.",
"validatingBetaText": "Validation de la beta...",
"validatingTestBuildText": "Validation de la Version Test...",
"viaText": "via",
"victoryText": "Victoire!",
"voteDelayText": "Vous ne pouvez commencer un autre vote que dans ${NUMBER} secondes",
"voteInProgressText": "Un vote est déjà en cours.",

View file

@ -871,6 +871,7 @@
"highText": "Hoch",
"higherText": "Höher",
"lowText": "Niedrig",
"maxFPSText": "Max FPS",
"mediumText": "Mittel",
"neverText": "Niemals",
"resolutionText": "Auflösung",

View file

@ -1,7 +1,7 @@
{
"accountRejectedText": "You ac woefije obj acwoew. Aj cowier wore cs?",
"accountSettingsWindow": {
"accountNameRules": "Acoief coej. c woejf. cwoef ocoweofwjfj c wjefowfowef wocjowefffz",
"accountNameRules": "Acoief coej. \n woejf. cwoef ocoweofwjfj c wjefowfowef wocjowefffz",
"accountProfileText": "(acczntl prfflzlf)",
"accountsText": "Acctntzz",
"achievementProgressText": "Achilfjasdflz: ${COUNT} ouzt of ${TOTAL}",
@ -34,6 +34,7 @@
"signInWithGooglePlayText": "Snf ocj weo fGOofl Plfl",
"signInWithTestAccountInfoText": "(lgjo cac cojef ot; oeco doic w eofjw oero )",
"signInWithTestAccountText": "Sjc weo fwtjwoefj cowefwf",
"signInWithText": "Sign fit cweof ${SERVICE}",
"signInWithV2InfoText": "(an zofj c woof woke wo Eire wf ofjjowg)",
"signInWithV2Text": "Sngo cow erwoj CBombSOudds acorjds.",
"signOutText": "Sgngz Ozt",
@ -342,6 +343,8 @@
"titleText": "Ádzd Gámzé",
"titleTextScale": 1.01
},
"addToFavoritesText": "Add owej owjwffwfwe",
"addedToFavoritesText": "Added '${NAME}' for cow jowdif.",
"allText": "Alcllwerf",
"allowText": "Alzéow",
"alreadySignedInText": "Yr co wcowief woeijo wife ewf;\norc woeful oj ceofjwoejfowief\nocjwoef weofwocijweofw.",
@ -378,6 +381,7 @@
"chatMutedText": "Chad mamba",
"chatUnMuteText": "Unobiaje Chafb",
"choosingPlayerText": "<chflzf plzlflr>",
"codesExplainText": "Cody wc woeir wcpwep oijwoeifj\nwoe wefjwe ofiwjeocijwoerer.",
"completeThisLevelToProceedText": "Yóz múst cómplítz\nthís lével tú próceed!",
"completionBonusText": "Cúmplezión Búnís",
"configControllersWindow": {
@ -467,6 +471,7 @@
"titleText": "Cónfígúre Tóuchszreen",
"touchControlsScaleText": "Tóuch Cóntróls Scále"
},
"configureDeviceInSystemSettingsText": "${DEVICE} otic w ejowei fajowe cjwoei woeirj dfwf.",
"configureItNowText": "Cónfígzre ít nów?",
"configureText": "Cónfúgzre",
"connectMobileDevicesWindow": {
@ -591,6 +596,8 @@
"disableXInputDescriptionText": "Allow mor wow ejo4 cow oeicjwo cobu oaf woejfowie jowrj",
"disableXInputText": "Dio cow eofwije",
"disabledText": "Dfewfczfwef",
"discordFriendsText": "Weor owe fwjeowi cow fowijfowjdfdf?\nJJowjef c jewel dODIj c jdjfosijfdfs!",
"discordJoinText": "JWeoj wc c wwdofijsd",
"doneText": "Dónz",
"drawText": "Drawz",
"duplicateText": "DSFcoiwjef",
@ -790,6 +797,7 @@
"manualYourLocalAddressText": "Yrrz lcl addratrz:",
"nearbyText": "Woiwjefd",
"noConnectionText": "<nz cnnectars>",
"noPartiesAddedText": "Not cower wo cowdj fwd",
"otherVersionsText": "(otco verosfjso)",
"partyCodeText": "Prewjr Cdfew",
"partyInviteAcceptText": "Acczlfp",
@ -873,10 +881,12 @@
"autoText": "Aúto",
"fullScreenCmdText": "Fúllézreen (Cmd-F)",
"fullScreenCtrlText": "Fúlzcréen (Ctrl-F)",
"fullScreenText": "Ffjoefzlefw",
"gammaText": "Gámza",
"highText": "Hígh",
"higherText": "Híghrz",
"lowText": "Lózw",
"maxFPSText": "Mxf cWEf",
"mediumText": "Mzdíum",
"neverText": "Névzer",
"resolutionText": "Résólution",
@ -1142,8 +1152,10 @@
"noExternalStorageErrorText": "Nz xtenrlf stlfsdf fnff onf thz dfvfojfzz",
"noGameCircleText": "Errór: nút lúggzd íntó Góme Cúrclz",
"noJoinCoopMidwayText": "Có-óp gúmzs cán't bz jóinzd mídwáy.",
"noPluginsInstalledText": "No Plugiwue sowiej fwdf",
"noProfilesErrorText": "Yoú hávz nó pláyerz prófilzs, só yóu're stzck wíth '${NAME}'.\nGó tz Sétzings->Pláyerz Prófiles tú mzke yóurszlf á prófile.",
"noScoresYetText": "Nz scrrlz ytz.",
"noServersFoundText": "Neo c who wj wo eij.",
"noThanksText": "Nó Thánkz",
"noTournamentsInTestBuildText": "WOREwr: WOTo cwoefw coif wefiidfjdf cow ekfwoejowijerwdifwdf.",
"noValidMapsErrorText": "Nó válíd máps fóund fúr thzs gáme typz.",
@ -1373,6 +1385,7 @@
"netTestingText": "Ntwkrz Tsstcg",
"resetText": "Rsttz",
"showBombTrajectoriesText": "Shzlz Bomf Tfwoejcwoefz",
"showDevConsoleButtonText": "Sho c weroiw c wo cwoije fwois",
"showInGamePingText": "Shoe o co fowl Png",
"showPlayerNamesText": "SHzlfjl Plzlrr Nmzlzlls",
"showUserModsText": "Shzl Mdsz Fldlrz",
@ -1468,6 +1481,8 @@
"storeText": "Stzlrle",
"submitText": "Scowiejfwef",
"submittingPromoCodeText": "Subjfoif Cdssz...",
"successText": "Sensded!",
"supportEmailText": "IF wc weoif joweij c woeifjowiejorwer\nc who we fweofiwjefo ${EMAIL}.",
"teamNamesColorText": "Tmcoj Conor/ Coarle...",
"teamsText": "Tééáémés",
"telnetAccessGrantedText": "Tzélnt acczzss énazledz.",
@ -1653,21 +1668,21 @@
"ChineseTraditional": "Cheifwoefjw Trwwefsdfs",
"Croatian": "Crrlzlrrs",
"Czech": "Czffef",
"Danish": "Dnishsdl",
"Danish": "Dnailöş",
"Dutch": "Dtchjdflz",
"English": "Englfjlzjsh",
"English": "Enfizikik",
"Esperanto": "Esprorjjzlz",
"Filipino": "Fefjwoeifj",
"Finnish": "Fnnizhsh",
"French": "Frnzhfhn",
"German": "Grmmzndn",
"Gibberish": "Gibberish",
"French": "Froktury",
"German": "Deutgwiz",
"Gibberish": "Abuktarika",
"Greek": "Gaofwef",
"Hindi": "Hfjofz",
"Hindi": "Panokallas",
"Hungarian": "Hngjgozf",
"Indonesian": "Inofiqdson",
"Italian": "Itzllfjssnn",
"Japanese": "Jpndjsjzes",
"Japanese": "Capnokas",
"Korean": "Kornesnzn",
"Malay": "FJwoerjjdf",
"Persian": "Psdfsdf",
@ -1676,12 +1691,12 @@
"Romanian": "Rmrfoijfzf",
"Russian": "Rzznrsn",
"Serbian": "Socowiejf",
"Slovak": "Slihdtbjoy",
"Spanish": "Snsdnsh",
"Slovak": "Zokkis",
"Spanish": "Snaddies",
"Swedish": "Swdiiszh",
"Tamil": "Tmfiewf",
"Thai": "Thzff",
"Turkish": "Twfoijwef",
"Turkish": "Turiyako",
"Ukrainian": "Ukckwef",
"Venetian": "Vwvowefdf",
"Vietnamese": "Vjefowiewer"
@ -1735,16 +1750,16 @@
"Ad view could not be verified.\nPlease be sure you are running an official and up-to-date version of the game.": "And foci wej fowif ijcowjer.\nPle eocj w jocose fowl jeowijeo few fj cijwoiejr. fofofifjow e ciweocywe.",
"An error has occurred; (${ERROR})": "An cow fc woof wcef; (${ERROR})",
"An error has occurred; please contact support. (${ERROR})": "An cowed c woefj wcoi woof weiojrwe rj goije ${ERROR})",
"An error has occurred; please contact support@froemling.net.": "An f oco ao ocio wj ; pocj oco woei fsuupo co co ifoiwnet",
"An error has occurred; please contact support@froemling.net.": "An f oco ao ocio wj ; pocj oco woei fsuupo co co ifoiwnet support@froemling.net gwizing patüköç.",
"An error has occurred; please try again later.": "An cowjef win woes owe p apowejrowjers.",
"Are you sure you want to link these accounts?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nThis cannot be undone!": "Ac woef oi eowic woiej fowije foijcwe?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nTHci weo woi efoiw ojo ij!!",
"BombSquad Pro unlocked!": "Boijfdfsjef pon occoijfs!",
"Can't link 2 accounts of this type.": "Cnoj' oi n aoco i ot oaifftz.",
"Can't link 2 diamond league accounts.": "Cnoi' oin koci o2 doi co fla cairjrs.",
"Can't link; would surpass maximum of ${COUNT} linked accounts.": "Cn't coi oi; could up vo io ${COUNT} oi c ioicoicuors.",
"Can't link; would surpass maximum of ${COUNT} linked accounts.": "Cn't coi oi; could up vo io möaksokato ${COUNT} oi c ioicoicuors.",
"Cheating detected; scores and prizes suspended for ${COUNT} days.": "Chowcj eof weoc jco; oe jwoeijf wojcwjeowfj woejf o${COUNT} dzf.",
"Could not establish a secure connection.": "Cjfoi cn ooi a tac c oweocoicoinr.",
"Daily maximum reached.": "Dfilaf mciwfjiwf rechced.",
"Daily maximum reached.": "Dfilaf möaksokato ravhgedök.",
"Entering tournament...": "Ernwoefijweo jfowjefw...",
"Invalid code.": "Invflijf cddz.",
"Invalid payment; purchase canceled.": "Info ejcwpeopwer; purwup cowefjwef.",
@ -1754,9 +1769,9 @@
"Item unlocked!": "Iwerw cowefjwoeijwer!",
"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)": "LINKING FOFJWEF. ${ACCOUNT} o iwjof\nowe oijwe c woeoijwf oAL FJOEJI OCJW.\nYou off leojwoer wcowe foiwjefojweoiwf\n(a c owfw oefjTHIS c weoojw oesf)",
"Link account ${ACCOUNT} to this account?\nAll existing data on ${ACCOUNT} will be lost.\nThis can not be undone. Are you sure?": "Lcjwe fwofj o ${ACCOUNT} to cowejfweof?\nAll wefoiwejtthosjic w ${ACCOUNT} cowiejf tjsl.\nThis wefowondot onsof. Aojr tyocu wsure?",
"Max number of playlists reached.": "Mx nfmow oijeplyalfaf rcnoahfd.",
"Max number of profiles reached.": "Mc fjpasdofj c owiejfowe oiwjefsd.",
"Maximum friend code rewards reached.": "Cmwoe oc wo Ego wel jacoweij weer.",
"Max number of playlists reached.": "Möaks nfmow oijeplyalfaf rcnoahfd.",
"Max number of profiles reached.": "Möks fresadora c owiejfowe rafgexed.",
"Maximum friend code rewards reached.": "Cmwoe oc wo Ego wel jacoweij weer möaksiöas.",
"Message is too long.": "CMew ociwje owe el.",
"No servers are available. Please try again soon.": "Ns seroiejwc wefjwoe wj. Ple wer wfwef ewfowes.",
"Profile \"${NAME}\" upgraded successfully.": "Profjojf \"${NAME}\" oupfuap coj woijsfsf.",
@ -1818,12 +1833,12 @@
"Flag Idle Return Time": "Flág Ídle Rétúrn Tímz",
"Flag Touch Return Time": "Flág Tzch Rétúrn Tímz",
"Hold Time": "Hólz Tímz",
"Kills to Win Per Player": "Kílls tó Wín Pér Plzáyer",
"Laps": "Lápz",
"Kills to Win Per Player": "Gebertzerto tórku Wenn Piérko Plzáyer",
"Laps": "Ląkzl",
"Lives Per Player": "Lívz Pérz Pláyrr",
"Long": "Lónggz",
"Longer": "Lóngrzz",
"Mine Spawning": "Míne Spáwning",
"Mine Spawning": "Mõvn okmalako",
"No Mines": "Nz Mfjfnzl",
"None": "Núnz",
"Normal": "Nórmzll",
@ -1842,10 +1857,10 @@
"Warning to ${NAME}: turbo / button-spamming knocks you out.": "Wjocief cwf ${NAME}: jojwo / ocjo efoiwefj wcoweok owerjoijdof."
},
"teamNames": {
"Bad Guys": "Bázd Gúyzs",
"Bad Guys": "Juardz gùårdz'n",
"Blue": "Blzúe",
"Good Guys": "Gzóod Gúys",
"Red": "Réd"
"Good Guys": "Gzóod Gùårdz'n",
"Red": "Vegco"
},
"tips": {
"A perfectly timed running-jumping-spin-punch can kill in a single hit\nand earn you lifelong respect from your friends.": "Á perfectly timed running-jumping-zpin-punch cán kill in á zingle hit\nánd eárn yóu lifelóng rezpect fróm yóur friendz.",
@ -1950,6 +1965,7 @@
"unlockThisInTheStoreText": "Thz mf voi eunlcoef owef joiefsfrwe.",
"unlockThisProfilesText": "To cowier co we ${NUM} pcoer, cow oicoj:",
"unlockThisText": "Tz ncowifj ocje, ycon fneeds:",
"unsupportedControllerText": "Sorwfw, contorlwef \"${NAME}\" oweifj wcjwoeir.",
"unsupportedHardwareText": "Srrz, thz hardwrz isz nt spprted bz thz vejerelr dlzl gmpzz.",
"upFirstText": "Uzp férzt:",
"upNextText": "Úp nézt ín gámz ${COUNT}:",
@ -1963,6 +1979,7 @@
"v2AccountLinkingInfoText": "To ljeowirj V2 sojowe, use fo 'Mnawefw Acoiwo' bons.",
"validatingBetaText": "Válúdztíng Bztá...",
"validatingTestBuildText": "Vldfjdfoi jtese-bsdfasfd...",
"viaText": "sdf",
"victoryText": "Vúctzry!",
"voteDelayText": "You caecowe oefo wocj woeiwo ${NUMBER} wocijwoef.",
"voteInProgressText": "A voiajf coiwje fwooeio wcwer.",

View file

@ -817,6 +817,7 @@
"highText": "Υψηλό",
"higherText": "Υψηλότερο",
"lowText": "Χαμηλό",
"maxFPSText": "Όριο FPS",
"mediumText": "Μέτριο",
"neverText": "Ποτέ",
"resolutionText": "Ανάλυση",
@ -1225,6 +1226,7 @@
"runText": "Τρέξιμο",
"saveText": "Αποθήκευση",
"scanScriptsErrorText": "Σφάλμα(α) κατά τη σάρωση σεναρίων. Δείτε το αρχείο καταγραφής για λεπτομέρειες.",
"scanScriptsSingleModuleNeedsUpdatesText": "Το ${PATH} χρειάζεται να αναβαθμιστεί για το api ${API}",
"scoreChallengesText": "Προκλήσεις Βαθμολογίας",
"scoreListUnavailableText": "Λίστα βαθμολογίας μη διαθέσιμη.",
"scoreText": "Βαθμολογία",
@ -1268,6 +1270,7 @@
"netTestingText": "Έλεγχος Δικτύου",
"resetText": "Επαναφορά",
"showBombTrajectoriesText": "Εμφάνιση Πορείας Βόμβας",
"showDevConsoleButtonText": "Εμφάνιση κονσόλας προγραμματιστών",
"showInGamePingText": "Εμφάνιση Καθυστέρησης Εντός-Παιχνιδιού",
"showPlayerNamesText": "Προβολή Ονομάτων Παικτών",
"showUserModsText": "Προβολή Φακέλου Πακέτων Τροποποίησης",

View file

@ -337,6 +337,7 @@
"getMoreGamesText": "और गेम्स कि जानकारी पायें",
"titleText": "गेम जोड़ें"
},
"allText": "सभी",
"allowText": "अनुमति दें",
"alreadySignedInText": "आपका खाता किसी अन्य डिवाइस से साइन किया गया है; \nकृपया खातों को स्विच करें या अपने गेम को अन्य डिवाइस \nपर बंद करें और फिर से प्रयास करें",
"apiVersionErrorText": "${NAME} मौड्यूल लोड नहीं हो पाया ; यह एपीआई - संस्करण ${VERSION_USED} पे काम करने का प्रयास कर रहा है ; हमें संस्करण ${VERSION_REQUIRED} चाहिए |",
@ -561,6 +562,7 @@
"disableRemoteAppConnectionsText": "रिमोट के ऐप्प कनेक्शन्स को बंद करे",
"disableXInputDescriptionText": "4 नियंत्रकों से अधिक की अनुमति देता है लेकिन साथ ही साथ काम नहीं कर सकते",
"disableXInputText": "Xinput अक्षम करें",
"disabledText": "डिसेबल्ड",
"doneText": "हो गया",
"drawText": "बराबर",
"duplicateText": "प्रतिलिपि",
@ -629,6 +631,7 @@
"useMusicFolderText": "गाने कि फाइल्स का फोल्डर"
},
"editText": "संपादित करें",
"enabledText": "इनेब्ल",
"endText": "समाप्त",
"enjoyText": "मज़ा लें !",
"epicDescriptionFilterText": "${DESCRIPTION} उत्कृष्ट धीमे गति में।",
@ -819,10 +822,12 @@
"alwaysText": "हमेशा",
"fullScreenCmdText": "संपूर्ण स्क्रीन में चलायें (सी-एम्-डी + ऍफ़)",
"fullScreenCtrlText": "संपूर्ण स्क्रीन में चलायें (सी-टी-आर-एल + ऍफ़)",
"fullScreenText": "पूर्ण स्क्रीन",
"gammaText": "चमक",
"highText": "ज्यादा",
"higherText": "और ज्यादा",
"lowText": "कम",
"maxFPSText": "अधिकतम एफ.पी.एस.",
"mediumText": "ठीक ठाक",
"neverText": "कभी नहीं",
"resolutionText": "रेज़ोल्यूशन",
@ -1064,6 +1069,7 @@
"noGameCircleText": "त्रुटी: गेम-सर्किल में लॉग-इन नहीं हैं |",
"noProfilesErrorText": "आपकी कोई खिलाड़ी पार्श्वचित्र नहीं है, इसलिए आप '${NAME}' नाम के साथ फंसे हैं |\nसेटिंग -> खिलाड़ी पार्श्वचित्र में जाके अपने लिए पार्श्वचित्र बनायें |",
"noScoresYetText": "अभी तक कोई स्कोर नहीं है |",
"noServersFoundText": "कोई सरवर्स नहीं मिलें।",
"noThanksText": "नहीं धन्यवाद",
"noTournamentsInTestBuildText": "चेतावनी: इस टेस्ट बिल्ड से खेलकूद-प्रतियोगिता के खेल के अंकों को नजरअंदाज कर दिया जाएगा।",
"noValidMapsErrorText": "इस गेम ढंग के लिए कोई नक्शा नहीं मिला",
@ -1229,6 +1235,8 @@
"runText": "दोडें",
"saveText": "सुरक्षित करें",
"scanScriptsErrorText": "स्क्रिप्ट्स स्कैन करने में गलती; विवरण के लिए लॉग देखें।",
"scanScriptsMultipleModulesNeedUpdatesText": "${PATH} और ${NUM} अन्य मॉड्यूल को ए.पी.आई. ${API} के लिए अद्यतन करने की आवश्यकता है।",
"scanScriptsSingleModuleNeedsUpdatesText": "एपीआई ${API} के लिए ${PATH} को अद्यतन करने की आवश्यकता है।",
"scoreChallengesText": "अंकों कि चुनौतियाँ",
"scoreListUnavailableText": "अंकों कि सूचि अभी उपस्थित नहीं है",
"scoreText": "अंक",
@ -1272,6 +1280,7 @@
"netTestingText": "नेटवर्क पर परीक्षण",
"resetText": "रीसेट",
"showBombTrajectoriesText": "बोम्ब का पथ दिखाएँ",
"showDevConsoleButtonText": "डेव कंसोल बटन दिखाएँ",
"showInGamePingText": "गेम पिंग में दिखाएं",
"showPlayerNamesText": "खिलाड़ी का नाम दिखाएँ",
"showUserModsText": "परिवर्तनों का फोल्डर दिखाएँ",
@ -1363,6 +1372,7 @@
"storeText": "दुकान",
"submitText": "जमा करें",
"submittingPromoCodeText": "संहिता जमा कर रहा है ...",
"successText": "सफल!",
"teamNamesColorText": "टीम के नाम / रंग ...",
"telnetAccessGrantedText": "टेलनेट एक्सेस सक्षम है",
"telnetAccessText": "टेलनेट पहुंच का पता चला; अनुमति देते हैं?",

View file

@ -31,6 +31,7 @@
"signInWithGooglePlayText": "Masuk menggunakan Google Play",
"signInWithTestAccountInfoText": "(akun tipe lama; gunakan akun device untuk kedepannya)",
"signInWithTestAccountText": "Masuk menggunakan akun percobaan",
"signInWithText": "Masuk dengan ${SERVICE}",
"signInWithV2InfoText": "(Akun yang berfungsi di semua akun)",
"signInWithV2Text": "Daftar dengan akun bombsquad",
"signOutText": "Keluar",
@ -367,6 +368,7 @@
"chatMutedText": "Percakapan Diabaikan",
"chatUnMuteText": "Menampilkan kembali percakapan",
"choosingPlayerText": "<memilih pemain>",
"codesExplainText": "Kode telah disediakan oleh pengembang\nuntuk didiagnosa dan memperbaiki isu akun.",
"completeThisLevelToProceedText": "Kamu harus menyelesaikan\nlevel ini untuk dapat lanjut!",
"completionBonusText": "Bonus Kelengkapan",
"configControllersWindow": {
@ -447,6 +449,7 @@
"swipeText": "geser",
"titleText": "Atur layar sentuh"
},
"configureDeviceInSystemSettingsText": "${DEVICE} dapat dikonfigurasikan pada aplikasi Pengaturan Sistem.",
"configureItNowText": "Atur sekarang?",
"configureText": "Konfigurasi",
"connectMobileDevicesWindow": {
@ -816,10 +819,12 @@
"alwaysText": "Selalu",
"fullScreenCmdText": "Layar Penuh (Cmd-F)",
"fullScreenCtrlText": "Layar Penuh (Ctrl+F)",
"fullScreenText": "Layar Penuh",
"gammaText": "Gamma",
"highText": "Tinggi",
"higherText": "Tertinggi",
"lowText": "Rendah",
"maxFPSText": "FPS Maks",
"mediumText": "Sedang",
"neverText": "Tak Pernah",
"resolutionText": "Resolusi",
@ -1061,6 +1066,7 @@
"noGameCircleText": "Kesalahan: tidak masuk ke LingkaranGame",
"noProfilesErrorText": "Kamu tidak punya profil pemain, jadi '${NAME}' dipakai. \nMasuk Pengaturan->Profil Pemain untuk membuat profil. ",
"noScoresYetText": "Belum ada skor.",
"noServersFoundText": "Server tidak ditemukan.",
"noThanksText": "Tidak, Terima kasih",
"noTournamentsInTestBuildText": "PERHATIAN: Skor turnamen dari build tes ini akan di abaikan",
"noValidMapsErrorText": "Tidak ada arena valid untuk game ini.",
@ -1271,6 +1277,7 @@
"netTestingText": "Tes Jaringan",
"resetText": "Atur ulang",
"showBombTrajectoriesText": "Lihat Lintasan Bom",
"showDevConsoleButtonText": "Tampilkan tombol Dev Console",
"showInGamePingText": "Tampilkan Ping dalam permainan",
"showPlayerNamesText": "Tunjukkan Nama Pemain",
"showUserModsText": "Lihat Folder Mod",
@ -1362,6 +1369,8 @@
"storeText": "Toko",
"submitText": "Serahkan",
"submittingPromoCodeText": "Menyerahkan Kode ...",
"successText": "Sukses!",
"supportEmailText": "Jika kamu mengalami masalah apa pun pada\naplikasi, mohon segera kirim email ${EMAIL}.",
"teamNamesColorText": "Nama Tim / Warna ...",
"telnetAccessGrantedText": "Akses telnet aktif.",
"telnetAccessText": "Akses telnet terdekteksi; izinkan?",
@ -1817,6 +1826,7 @@
"unlockThisInTheStoreText": "Tersedia di toko terdekat.",
"unlockThisProfilesText": "Untuk membuat lebih dari ${NUM} profil, Kamu memerlukan:",
"unlockThisText": "Untuk buka ini,kamu membutuhkan:",
"unsupportedControllerText": "Maaf, kontroler \"${NAME}\" tidak mendukung.",
"unsupportedHardwareText": "Maaf, perangkat ini tidak mendukung build permainan ini.",
"upFirstText": "Game pertama:",
"upNextText": "${COUNT} game berikutnya:",
@ -1829,6 +1839,7 @@
"usingItunesTurnRepeatAndShuffleOnText": "Tolong pastikan lagu diacak dan diulang di iTunes. ",
"v2AccountLinkingInfoText": "Untuk menautkan akun V2, gunakan tombol 'Manajemen Akun'.",
"validatingTestBuildText": "Memvalidasi Bangunan Tes...",
"viaText": "melalui",
"victoryText": "Menang!",
"voteDelayText": "Kamu tidak dapat memulai pemilihan suara dalam ${NUMBER} detik",
"voteInProgressText": "Pemilihan suara sedang dalam proses.",

View file

@ -17,7 +17,7 @@
"linkAccountsInstructionsText": "Per collegare due account, crea un codice su uno\ndei dispositivi e inserisci quel codice negli altri. \nProgressi e inventario verranno combinati.\nPuoi collegare fino a ${COUNT} account.\n\nIMPORTANTE: Collega solo account che possiedi!\nSe colleghi un account con un tuo amico non potrete\ngiocare allo stesso momento!\n \nInoltre: questa operazione non può essere annullata, quindi stai attento!",
"linkAccountsText": "Collega account",
"linkedAccountsText": "Account Collegati:",
"manageAccountText": "Gestisci account",
"manageAccountText": "Gestisci Account",
"nameChangeConfirm": "Confermi di voler modificare il tuo nome in ${NAME}?",
"notLoggedInText": "<accesso non effettuato>",
"resetProgressConfirmNoAchievementsText": "Stai per cancellare i tuoi progressi in\nmodalità cooperativa, i tuoi obbiettivi, i tuoi punteggi\nlocali (ma non i tuoi biglietti). \n\nL'operazione è irreversibile: continuare?",
@ -33,6 +33,7 @@
"signInWithGooglePlayText": "Accedi con Google Play",
"signInWithTestAccountInfoText": "(tipo di account obsoleto; usa gli account dispositivo d'ora in poi)",
"signInWithTestAccountText": "Accedi con un account di prova",
"signInWithText": "Accedi con ${SERVICE}",
"signInWithV2InfoText": "(un account che funziona su tutte le piattaforme)",
"signInWithV2Text": "Effettua l'accesso con un account di BombSquad",
"signOutText": "Esci",
@ -340,6 +341,8 @@
"getMoreGamesText": "Ottieni Giochi...",
"titleText": "Aggiungi Partita"
},
"addToFavoritesText": "Aggiungi ai Preferiti",
"addedToFavoritesText": "'${NAME}' aggiunto ai Preferiti",
"allText": "Tutto",
"allowText": "Consenti",
"alreadySignedInText": "Il tuo account è collegato da un altro dispositivo;\ncambia account o chiudi il gioco nel tuo altro\ndispositivo e riprova.",
@ -376,6 +379,7 @@
"chatMutedText": "Chat Silenziata",
"chatUnMuteText": "Smuta Chat",
"choosingPlayerText": "<scelta giocatore>",
"codesExplainText": "i codici sono forniti dallo sviluppatore per\nscoprire e correggere problemi all'account.",
"completeThisLevelToProceedText": "Devi completare questo\nlivello per procedere!",
"completionBonusText": "Competizione bonus",
"configControllersWindow": {
@ -459,6 +463,7 @@
"titleText": "Configura il Touchscreen",
"touchControlsScaleText": "Scala dei Comandi Touch"
},
"configureDeviceInSystemSettingsText": "${DEVICE} può essere configurato nelle Impostazioni di Sistema.",
"configureItNowText": "Configurarlo adesso?",
"configureText": "Configura",
"connectMobileDevicesWindow": {
@ -580,6 +585,8 @@
"disableXInputDescriptionText": "Permette l'uso di più di 4 pulsantiere, ma potrebbe anche non funzionare.",
"disableXInputText": "Disabilita XInput",
"disabledText": "DISABILITATO",
"discordFriendsText": "Cerchi altri con cui giocare?\nEntra nel nostro server Discord e fatti nuovi amici!",
"discordJoinText": "Entra nel server Discord",
"doneText": "Fatto",
"drawText": "Pareggio",
"duplicateText": "Duplicato",
@ -776,6 +783,7 @@
"manualYourLocalAddressText": "Indirizzo locale:",
"nearbyText": "Locale",
"noConnectionText": "<nessuna connessione>",
"noPartiesAddedText": "Nessun Party Aggiunto",
"otherVersionsText": "(altre versioni)",
"partyCodeText": "Codice del Party",
"partyInviteAcceptText": "Accetta",
@ -856,16 +864,18 @@
"autoText": "Automatico",
"fullScreenCmdText": "Schermo intero (Cmd-F)",
"fullScreenCtrlText": "Schermo intero (Ctrl-F)",
"fullScreenText": "Schermo intero",
"gammaText": "Gamma",
"highText": "Alto",
"higherText": "Più alto",
"lowText": "Basso",
"maxFPSText": "FPS massimi",
"mediumText": "Medio",
"neverText": "Mai",
"resolutionText": "Risoluzione",
"showFPSText": "Mostra FPS",
"texturesText": "Textures",
"titleText": "Grafiche",
"titleText": "Grafica",
"tvBorderText": "Bordo della TV",
"verticalSyncText": "Sincronizzazione verticale",
"visualsText": "Visuali"
@ -1106,8 +1116,10 @@
"noExternalStorageErrorText": "Nessun archiviatore esterno trovato su questo dispositivo",
"noGameCircleText": "Errore: non hai effettuato il login su GameCircle",
"noJoinCoopMidwayText": "Non puoi entrare in una partita cooperativa già iniziata.",
"noPluginsInstalledText": "Nessun Plugin Installato",
"noProfilesErrorText": "Non hai un profilo giocatore, quindi sei bloccato con '${NAME}'.\nVai su Impostazioni > Profili giocatore per creare un profilo personale.",
"noScoresYetText": "Ancora nessun punteggio.",
"noServersFoundText": "Nessun server individuato.",
"noThanksText": "No Grazie",
"noTournamentsInTestBuildText": "I punteggi del torneo di questo test build verranno ignorati",
"noValidMapsErrorText": "Non sono state trovate mappe valide per questo tipo di gioco.",
@ -1327,6 +1339,7 @@
"netTestingText": "Collaudo Rete",
"resetText": "Reset",
"showBombTrajectoriesText": "Mostra le traiettorie delle bombe",
"showDevConsoleButtonText": "mostra tasto console sviluppatore",
"showInGamePingText": "Mostra il Ping in gioco",
"showPlayerNamesText": "Mostra i nomi dei giocatori",
"showUserModsText": "Apri cartella personalizzazioni",
@ -1422,6 +1435,8 @@
"storeText": "Negozio",
"submitText": "Inoltra",
"submittingPromoCodeText": "Inoltrando il Codice...",
"successText": "Fatto!",
"supportEmailText": "Se riscontri problemi con l'app,\nper favore scrivi a ${EMAIL}.",
"teamNamesColorText": "Colore/Nome Team",
"teamsText": "Squadre",
"telnetAccessGrantedText": "Accesso a telnet abilitato",
@ -1715,7 +1730,7 @@
"Profile \"${NAME}\" upgraded successfully.": "Il profilo \"${NAME}\" è stato aggiornato con successo.",
"Profile could not be upgraded.": "Il profilo non è potuto essere aggiornato.",
"Purchase successful!": "Acquistato con successo!",
"Received ${COUNT} tickets for signing in.\nCome back tomorrow to receive ${TOMORROW_COUNT}.": "Ricevi ${COUNT} biglietti accedendo.\nTorna domani per ricevere ${TOMORROW_COUNT}.",
"Received ${COUNT} tickets for signing in.\nCome back tomorrow to receive ${TOMORROW_COUNT}.": "Ricevi ${COUNT} biglietti accedendo.\nTorna domani per riceverne ${TOMORROW_COUNT}.",
"Server functionality is no longer supported in this version of the game;\nPlease update to a newer version.": "La funzionalità server non è più supportata in questa versione del gioco;\nAggiornalo ad una nuova versione.",
"Sorry, there are no uses remaining on this code.": "Spiacente, non ci sono altri utilizzi rimasti su questo codice.",
"Sorry, this code has already been used.": "Spiacente, questo codice è già stato usato.",
@ -1903,6 +1918,7 @@
"unlockThisInTheStoreText": "Deve essere sbloccato nel negozio",
"unlockThisProfilesText": "Per creare più di ${NUM} profili, ti serve:",
"unlockThisText": "Per sbloccare questo, hai bisogno di:",
"unsupportedControllerText": "Spiacente, il controller \"${NAME}\" non è supportato.",
"unsupportedHardwareText": "Purtroppo, questo hardware non è supportato da questa versione del gioco.",
"upFirstText": "Per primo:",
"upNextText": "Fra poco nel ${COUNT}:",
@ -1916,6 +1932,7 @@
"v2AccountLinkingInfoText": "Per collegare degli account V2, usa il tasto 'Gestisci Account'.",
"validatingBetaText": "Sto convalidando la beta...",
"validatingTestBuildText": "Convalida Build Di Prova...",
"viaText": "utilizzando",
"victoryText": "Vittoria!",
"voteDelayText": "Non puoi cominciare un'altra votazione per ${NUMBER} secondi",
"voteInProgressText": "C'è già una votazione in corso.",

View file

@ -31,6 +31,7 @@
"signInWithGooglePlayText": "Google Play로 로그인",
"signInWithTestAccountInfoText": "(이전 계정 유형, 앞의 기기 계정을 이용하세요)",
"signInWithTestAccountText": "테스트 계정으로 로그인",
"signInWithText": "${SERVICE}로 로그인하기",
"signInWithV2InfoText": "(모든 플랫폼에서 작동하는 계정입니다)",
"signInWithV2Text": "BombSquad 계정으로 로그인",
"signOutText": "로그아웃",
@ -335,6 +336,7 @@
"getMoreGamesText": "다른 게임 보기...",
"titleText": "게임 추가"
},
"allText": "모두",
"allowText": "허용",
"alreadySignedInText": "귀하의 계정은 다른 기기에서 로그인되었습니다. \n계정을 전환하거나 다른 기기에서 게임을 종료하고 \n다시 시도하십시오.",
"apiVersionErrorText": "${NAME} 모듈을 불러올 수 없습니다; ${VERSION_USED} api 버전입니다; ${VERSION_REQUIRED} 버전이 필요합니다.",
@ -367,6 +369,7 @@
"chatMutedText": "채팅 음소거됨.",
"chatUnMuteText": "채팅 음소거 해제",
"choosingPlayerText": "<플레이어 선택>",
"codesExplainText": "계정 문제를 진단하고 수정하기 위해\n개발자가 코드를 제공합니다.",
"completeThisLevelToProceedText": "계속 진행하려면 이 레벨을\n완료해야 합니다!",
"completionBonusText": "완료 보너스",
"configControllersWindow": {
@ -447,6 +450,7 @@
"swipeText": "스와이프",
"titleText": "터치스크린 구성"
},
"configureDeviceInSystemSettingsText": "${DEVICE}는 시스템 설정 앱에서 구성할 수 있습니다.",
"configureItNowText": "지금 구성하시겠습니까?",
"configureText": "구성",
"connectMobileDevicesWindow": {
@ -559,6 +563,9 @@
"disableRemoteAppConnectionsText": "리모트 앱 연결 비활성화",
"disableXInputDescriptionText": "4개 이상의 컨트롤러를 허용하지만 아마 잘 작동하지 않을 것입니다.",
"disableXInputText": "엑스인풋 컨트롤러 비활성화",
"disabledText": "비활성화만",
"discordFriendsText": "함께 플레이할 새로운 친구를 찾고 싶으신가요?\n디스코드에 가입하여 새로운 친구를 찾아보세요!",
"discordJoinText": "디스코드 가입",
"doneText": "완료",
"drawText": "무승부",
"duplicateText": "복사",
@ -626,6 +633,7 @@
"useMusicFolderText": "음악 파일 폴더"
},
"editText": "편집",
"enabledText": "활성화만",
"endText": "종료",
"enjoyText": "즐기세요!",
"epicDescriptionFilterText": "(에픽 슬로 모션) ${DESCRIPTION}.",
@ -814,10 +822,12 @@
"alwaysText": "언제나",
"fullScreenCmdText": "전체 화면 (Cmd-F)",
"fullScreenCtrlText": "전체 화면 (Ctrl-F)",
"fullScreenText": "전체화면",
"gammaText": "감마",
"highText": "높음",
"higherText": "매우 높음",
"lowText": "낮음",
"maxFPSText": "최대 FPS",
"mediumText": "중간",
"neverText": "안 함",
"resolutionText": "해상도",
@ -1056,6 +1066,7 @@
"noExternalStorageErrorText": "이 기기에서 외부 저장소를 찾지 못했습니다.",
"noGameCircleText": "오류: GameCircle에 로그인되지 않았습니다",
"noScoresYetText": "아직 점수 없음.",
"noServersFoundText": "서버를 찾을수 없음.",
"noThanksText": "아니요",
"noTournamentsInTestBuildText": "경고: 이 테스트 빌드의 토너먼트 점수는 기록되지 않습니다.",
"noValidMapsErrorText": "이 게임 유형에 유효한 지도를 찾지 못했습니다.",
@ -1220,6 +1231,8 @@
"runText": "달리기",
"saveText": "저장",
"scanScriptsErrorText": "스크립트(들)을 검색하는 중 오류가 발생하였습니다. 자세한 내용은 로그를 확인하십시오.",
"scanScriptsMultipleModulesNeedUpdatesText": "${PATH} 및 ${NUM}개의 기타 모듈을 ${API} API에 대해 업데이트를 해야 합니다.",
"scanScriptsSingleModuleNeedsUpdatesText": "${PATH}는 api ${API}에 대해 업데이트해야 합니다.",
"scoreChallengesText": "점수 챌린지",
"scoreListUnavailableText": "점수 목록을 이용할 수 없습니다.",
"scoreText": "점수",
@ -1263,6 +1276,7 @@
"netTestingText": "네트워크 테스트",
"resetText": "재설정",
"showBombTrajectoriesText": "폭탄 궤적 표시",
"showDevConsoleButtonText": "개발자 콘솔 버튼 보이기",
"showInGamePingText": "인게임 핑 보이기",
"showPlayerNamesText": "플레이어 이름 표시",
"showUserModsText": "모드 폴더 표시",
@ -1355,6 +1369,8 @@
"storeText": "상점",
"submitText": "제출",
"submittingPromoCodeText": "코드 제출 중...",
"successText": "성공!",
"supportEmailText": "만약 앱에서 문제를 겪고있을경우,\n${EMAIL}로 연락해주세요",
"teamNamesColorText": "팀 이름/색상...",
"telnetAccessGrantedText": "텔넷 액세스가 활성화됨.",
"telnetAccessText": "텔넷 액세스가 검색됨, 허용하시겠습니까?",
@ -1808,6 +1824,7 @@
"unlockThisInTheStoreText": "상점에서 잠금 해제해야 합니다.",
"unlockThisProfilesText": "${NUM}개 이상의 프로필을 만들기 위해, 다음 사항이 필요합니다. :",
"unlockThisText": "잠금 해제 필요 사항:",
"unsupportedControllerText": "죄송합니다, 컨트롤러 \"${NAME}\" 은 지원되지 않습니다.",
"unsupportedHardwareText": "죄송합니다만 이 하드웨어는 본 게임 빌드에 의해 지원되지 않습니다.",
"upFirstText": "첫 번째:",
"upNextText": "게임 ${COUNT}의 다음:",
@ -1820,6 +1837,7 @@
"usingItunesTurnRepeatAndShuffleOnText": "iTunes에서 임의 재생이 켜져있고 반복은 모두로 되어 있는지 확인해주십시오.",
"v2AccountLinkingInfoText": "V2 계정을 연결하려면 '계정 관리' 버튼을 누르세요.",
"validatingTestBuildText": "테스트 빌드 확인 중...",
"viaText": "통하여 로그인 함",
"victoryText": "승리!",
"voteDelayText": "${NUMBER} 초 동안 다른 투표를 시작할 수 없습니다.",
"voteInProgressText": "투표가 이미 진행 중입니다.",

View file

@ -31,6 +31,7 @@
"signInWithGooglePlayText": "ورود با اکانت گوگل پلی",
"signInWithTestAccountInfoText": "(حساب میراثی؛ از حساب‌های دستگاه برای پیشروی استفاده می‌کند)",
"signInWithTestAccountText": "ورود با حساب آزمایشی",
"signInWithText": "با ${SERVICE} وارد شوید",
"signInWithV2InfoText": "یک اکانت که روی همه سیستم عامل ها کار میکنه",
"signInWithV2Text": "ورود به سیستم با حساب بمب اسکواد",
"signOutText": "خروج از حساب",
@ -60,7 +61,7 @@
"descriptionComplete": "بدون استفاده از بمب برنده شدی",
"descriptionFull": "را بدون استفاده از هیچ بمبی کامل کن ${LEVEL} مرحلهٔ",
"descriptionFullComplete": "را بدون استفاده از بمب کامل کردی ${LEVEL} مرحلهٔ",
"name": "بوکسر"
"name": "بوکسور!"
},
"Dual Wielding": {
"descriptionFull": "(‏دو دستهٔ به بازی وصل کن (سخت‌افزاری یا نرم‌افزاری",
@ -124,7 +125,7 @@
"descriptionComplete": "سه حریف را با مین زمینی از بین بردی",
"descriptionFull": "با مین از بین ببر ${LEVEL} سه حریف را در مرحلهٔ",
"descriptionFullComplete": "با مین از بین بردی ${LEVEL} سه حریف را در مرحلهٔ",
"name": "بازی مین"
"name": "مین بازی"
},
"Off You Go Then": {
"description": "سه تا حریف از نقشه بنداز بیرون",
@ -262,7 +263,7 @@
"descriptionComplete": "فقط با یک مشت، یه نفرو کشتی",
"descriptionFull": "فقط با یک مشت، یه نفر رو نابود کن ${LEVEL} در مرحله",
"descriptionFullComplete": "فقط با یک مشت، یه نفر رو کشتی ${LEVEL} در مرحله",
"name": "مشت فوق‌العاده"
"name": "مشت خیلی فوق‌العاده"
},
"Super Punch": {
"description": "با یک مشت، نصف جون یه نفر رو ببر",
@ -334,12 +335,14 @@
"getMoreGamesText": "...بازی های بیشتر",
"titleText": "افزودن بازی"
},
"addToFavoritesText": "اضافه کردن به مورد علاقه ها",
"addedToFavoritesText": "اضافه شد '${NAME}' به مورد علاقه ها",
"allText": "همه",
"allowText": "اجازه دادن",
"alreadySignedInText": "این حساب کاربری توسط یک دستگاه دیگر در حال استفاده می باشد.\nلطفا از حساب کاربری دیگری استفاده کنید یا بازی را \nدر بقیه دستگاه هایتان ببندید و دوباره امتحان کنید.",
"apiVersionErrorText": "نیاز داریم ${VERSION_REQUIRED} است. به ورژن ${VERSION_USED} بالا نمی آید. هدفش ${NAME} مدل",
"audioSettingsWindow": {
"headRelativeVRAudioInfoText": "(به صورت اتوماتیک فعال شود وقتی که هدفون متصل است)",
"headRelativeVRAudioInfoText": "(به صورت خودکار فعال شود وقتی که هدفون متصل است)",
"headRelativeVRAudioText": "(صدای واقعیت مجازی(مخصوص هدفون",
"musicVolumeText": "صدای موسیقی",
"soundVolumeText": "صدای بازی",
@ -367,6 +370,7 @@
"chatMutedText": "گفتگو بیصدا شد",
"chatUnMuteText": "گفتگو رو صدادار کن",
"choosingPlayerText": "<انتخاب بازیکن>",
"codesExplainText": "کدها توسط توسعه دهنده ارائه می شوند\n مشکلات حساب را تشخیص و تصحیح کنید.",
"completeThisLevelToProceedText": "برای ادامه باید این مرحله را تمام کنید",
"completionBonusText": "پاداش به اتمام رساندن",
"configControllersWindow": {
@ -448,6 +452,7 @@
"swipeText": "حرکت جاروبی",
"titleText": "پیکربندی صفحه لمسی"
},
"configureDeviceInSystemSettingsText": "${DEVICE} می‌تواند در سیستم تنظیمات برنامه پیکربندی شود.",
"configureItNowText": "همین الآن تنظیم شود ؟",
"configureText": "پیکربندی",
"connectMobileDevicesWindow": {
@ -562,6 +567,8 @@
"disableXInputDescriptionText": "اجازه می‌دهد به بیش از 4 کنترل کننده اما ممکن است کار نکند.",
"disableXInputText": "غیرفعال کردن ورودی ایکس",
"disabledText": "غیر فعال شده",
"discordFriendsText": "دنبال آدم‌های جدید می‌گردید تا با آنها بازی کنید؟\nبه دیسکورد ما بپیوندید و دوستان جدید پیدا کنید!",
"discordJoinText": "پیوستن به دیسکورد",
"doneText": "انجام شد",
"drawText": "برابر",
"duplicateText": "تکراری",
@ -747,6 +754,7 @@
"manualYourLocalAddressText": ":آدرس محلی شما",
"nearbyText": "افراد نزدیک",
"noConnectionText": "<اتصال برقرار نیست>",
"noPartiesAddedText": "هیچ مهمانی ای اضافه نشده است",
"otherVersionsText": "(نسخه های دیگر)",
"partyCodeText": "کد گروه",
"partyInviteAcceptText": "پذیرفتن",
@ -818,10 +826,12 @@
"alwaysText": "همیشه",
"fullScreenCmdText": "تمام صفحه (Cmd-F)",
"fullScreenCtrlText": "تمام صفحه (Ctrl-F)",
"fullScreenText": "تمام‌صفحه",
"gammaText": "گاما",
"highText": "زیاد",
"higherText": "بالاتر",
"lowText": "کم",
"maxFPSText": "حداکثر FPS",
"mediumText": "معمولی",
"neverText": "هرگز",
"resolutionText": "رزولوشن",
@ -1059,7 +1069,9 @@
"noContinuesText": "(ادامه ندارد)",
"noExternalStorageErrorText": "محل ذخیره سازی در این دستگاه یافت نشد",
"noGameCircleText": "GameCircleخطا: وارد نشدید به",
"noPluginsInstalledText": "متاسفانه پلاگین ها نصب نشده",
"noScoresYetText": "هیچ امتیازی نیست",
"noServersFoundText": "سروری (شبکه ای) یافت نشد",
"noThanksText": "نه مرسی",
"noTournamentsInTestBuildText": ".هشدار: امتیازات مسابقه از این نسخهٔ آزمایشی نادیده گرفته می‌شوند",
"noValidMapsErrorText": "هیچ نقشه معتبری برای این نوع بازی یافت نشد.",
@ -1269,6 +1281,7 @@
"netTestingText": "تست شبکه",
"resetText": "باز گرداندن",
"showBombTrajectoriesText": "نمایش خط سیر بمب",
"showDevConsoleButtonText": "نشان دادن دکمه توسعه دهنده کنسول",
"showInGamePingText": "نمایش پینگ در بازی",
"showPlayerNamesText": "نمایش نام بازیکنان",
"showUserModsText": "نمایش پوشهٔ سبک بازی‌ها",
@ -1361,6 +1374,8 @@
"storeText": "فروشگاه",
"submitText": "ثبت",
"submittingPromoCodeText": "...ثبت کردن کد",
"successText": "!موفقیت آمیز بود",
"supportEmailText": "اگر با هر گونه مشکلی مواجه هستید\n برنامه، لطفاً به ${EMAIL} ایمیل بزنید.",
"teamNamesColorText": "نام/رنگ تیم...",
"telnetAccessGrantedText": "شبکه ی در دسترس فعال",
"telnetAccessText": "شبکه راه دور دردسترس است اجازه میدید؟",
@ -1371,7 +1386,7 @@
"thankYouText": "تشکر بخاطر حمایت از ما ! از بازی لذت ببرید",
"threeKillText": "نابود کردن همزمان سه نفر",
"timeBonusText": "پاداش سرعت عمل",
"timeElapsedText": "زمان سپری شده",
"timeElapsedText": "زمان گذشته",
"timeExpiredText": "زمان تمام شده",
"timeSuffixDaysText": "روز ${COUNT}",
"timeSuffixHoursText": "ساعت ${COUNT}",
@ -1737,7 +1752,7 @@
"If you pick up a curse, your only hope for survival is to\nfind a health powerup in the next few seconds.": "اگه یه جعبه نابودگر رو به اشتباه گرفتین کارتون تمومه مگه اینکه ظرف چند\nثانیه یه جعبه ی درمان گیر بیارید",
"If you stay in one place, you're toast. Run and dodge to survive..": "اگه فقط توی یه مکان ثابت بمونید کباب میشید پس بهتره مرتب توی زمین تحرک داشته باشی",
"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.": "اگر تعداد زیادی از بازیکنان در حال رفت و آمد هستند، بازیکنان \"بیروت انداختن بازیکنان غیرفعال\" را روشن کنید\nتحت تنظیمات در صورتی که کسی فراموش می‌کندپیش از خروج از بازی ترک بازی را بزند.",
"If your device gets too warm or you'd like to conserve battery power,\nturn down \"Visuals\" or \"Resolution\" in Settings->Graphics": "اگر دستگاه شما بیش از حد گرم می شود یا شما می خواهید برای حفظ قدرت باتری،\nکم کنید \"کیفیت\" یا \"وضوح تصویر\" رو در تنظیمات> گرافیک",
"If your device gets too warm or you'd like to conserve battery power,\nturn down \"Visuals\" or \"Resolution\" in Settings->Graphics": "اگر دستگاه شما بیش از حد گرم می شود یا شما می خواهید برای حفظ قدرت باتری،\n\"کیفیت\" یا \"وضوح تصویر\" رو در تنظیمات> گرافیک\nکم کنید",
"If your framerate is choppy, try turning down resolution\nor visuals in the game's graphics settings.": "اگر دیدید که نرخ فریم تصویر کمی متلاطم است کاهش بدید رزولوشن \nیا کیفیت تصویر رو در تنظیمات گرافیک بازی",
"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.": "توی بازی رساندن پرچم ، باید پرچم تیم شما همون جا باقی بمونه\nاگه تیم حریف پرچم تیم شما رو برداشت باید از دستش کش بری",
"In hockey, you'll maintain more speed if you turn gradually.": "روی زمین های یخی ، یه دفعه چرخیدن خیلی از سرعت بازیکن کم میکنه",
@ -1816,6 +1831,7 @@
"unlockThisInTheStoreText": ". این مورد باید در فروشگاه باز شود",
"unlockThisProfilesText": "برای ایجاد بیش از ${NUM} پروفال٫ احتیاج به این موارد دارید:",
"unlockThisText": ": برا باز کردن قفل این شما نیاز دارید که",
"unsupportedControllerText": "متاسفانه کنترلر \"${NAME}\" پشتیبانی نمی‌شود.",
"unsupportedHardwareText": "با عرض پوزش، این سخت افزار توسط این ساخت بازی پشتیبانی نمی شود.",
"upFirstText": "برای بار اول:",
"upNextText": "${COUNT} بعدی در بازی",
@ -1828,6 +1844,7 @@
"usingItunesTurnRepeatAndShuffleOnText": "مطمین شید که شافل روشن است و تکرار کنید همه رو در آیتونز",
"v2AccountLinkingInfoText": "برای پیوند دادن حساب‌های V2، از دکمه «مدیریت حساب» استفاده کنید.",
"validatingTestBuildText": "... در حال بررسی حالت آزمایشی",
"viaText": "از طریق",
"victoryText": "پیروز شدی!",
"voteDelayText": ".ثانیه رای گیری کنید ${NUMBER} شما نمیتوانید به مدت",
"voteInProgressText": ".یک رای گیری در حال انجام است",

View file

@ -1,18 +1,18 @@
{
"accountSettingsWindow": {
"accountNameRules": "Nazwy kont nie mogą zawierać emotikonków ani innych znaków specjalnych",
"accountNameRules": "Nazwy kont nie mogą zawierać emotikonów ani innych znaków specjalnych",
"accountProfileText": "(profil konta)",
"accountsText": "Konta",
"achievementProgressText": "Osiągnięcia: ${COUNT} z ${TOTAL}",
"campaignProgressText": "Postęp Kampanii [Trudny]: ${PROGRESS}",
"changeOncePerSeason": "Możesz to zmienić tylko raz na sezon.",
"changeOncePerSeasonError": "Musisz poczekać do następnego sezonu by znowu to zmienić (${NUM} dni)",
"customName": "Losowa Nazwa",
"changeOncePerSeasonError": "Musisz poczekać do następnego sezonu, by znowu to zmienić (${NUM} dni)",
"customName": "Własna Nazwa",
"googlePlayGamesAccountSwitchText": "Jeśli chcesz użyć innego konta Google,\nużyj aplikacji Gry Google Play, aby przełączyć się na to konto.",
"linkAccountsEnterCodeText": "Wpisz Kod",
"linkAccountsGenerateCodeText": "Wygeneruj Kod",
"linkAccountsInfoText": "(przenoś postęp między różnymi platformami)",
"linkAccountsInstructionsNewText": "Aby połączyć dwa konta, wygeneruj kod na pierwszym,\ni wpisz ten kod na drugim. Postęp z drugiego\nbędzie podzielony między oba konta.\n(Postęp z pierwszego zostanie utracony)\n\nMożesz połączyć do ${COUNT} kont.\n\nWAŻNE: łącz tylko swoje własne konta;\nJeśli łączysz konto ze znajomym, nie będziecie\nmogli grać przez internet w tym samym czasie.",
"linkAccountsInstructionsNewText": "Aby połączyć dwa konta, wygeneruj kod na pierwszym\ni wpisz ten kod na drugim. Postęp z drugiego\nbędzie podzielony między oba konta.\n(Postęp z pierwszego konta zostanie utracony)\n\nMożesz połączyć do ${COUNT} kont.\n\nWAŻNE: łącz tylko swoje własne konta;\nJeśli łączysz konto ze znajomym, nie będziecie\nmogli grać przez internet w tym samym czasie.",
"linkAccountsInstructionsText": "By połączyć dwa konta, wygeneruj kod\nna jednym z nich i wpisz na drugim.\nPostęp i ekwipunek zostaną połączone.\nMożesz połączyć do ${COUNT} kont.\n\nUWAGA: Łącz tylko konta, które należą do Ciebie!\nJeśli połączysz konto z przyjacielem,\nnie będziecie mogli grać w tym samym czasie!\n\nAktualnie nie można tego cofnąć, więc uważaj!",
"linkAccountsText": "Połącz Konta",
"linkedAccountsText": "Połączone Konta:",
@ -24,19 +24,20 @@
"resetProgressText": "Wyczyść postęp",
"setAccountName": "Wybierz nazwę konta",
"setAccountNameDesc": "Wybierz nazwę do wyświetlenia dla swojego konta.\nMożesz użyć nazwy z jednego z połączonych kont\n lub utworzyć unikalną niestandardową nazwę.",
"signInInfoText": "Zapisz się, by zbierać kupony, rywalizować online\ni przenosić postęp gry między urządzeniami",
"signInText": "Zapisz się",
"signInInfoText": "Zaloguj się, by zbierać kupony, rywalizować online\ni przenosić postęp gry między urządzeniami",
"signInText": "Zaloguj się",
"signInWithDeviceInfoText": "(automatyczne konto dostępne tylko z tego urządzenia)",
"signInWithDeviceText": "Zapisz się kontem z urządzenia.",
"signInWithGameCircleText": "Zapisz się z Game Circle",
"signInWithGooglePlayText": "Zapisz się kontem Google Play",
"signInWithTestAccountInfoText": "Konto.",
"signInWithTestAccountText": "Zapisz się testowym kontem.",
"signInWithDeviceText": "Zaloguj się kontem urządzenia",
"signInWithGameCircleText": "Zaloguj się z Game Circle",
"signInWithGooglePlayText": "Zaloguj się kontem Google Play",
"signInWithTestAccountInfoText": "(przestarzały typ konta; w przyszłości używaj konta urządzenia)",
"signInWithTestAccountText": "Zaloguj się kontem testowym",
"signInWithText": "Zaloguj się kontem ${SERVICE}",
"signInWithV2InfoText": "(konto działa na wszystkich platformach)",
"signInWithV2Text": "Zaloguj się używając konta BombSquad",
"signInWithV2Text": "Zaloguj się kontem BombSquad",
"signOutText": "Wypisz się",
"signingInText": "Zapisywanie się...",
"signingOutText": "Wypisywanie...",
"signingInText": "Trwa logowanie...",
"signingOutText": "Trwa wylogowywanie...",
"testAccountWarningCardboardText": "Ostrzeżenie: Zapisujesz się przy użyciu konta \"test\".\nZostanie ono zastąpione kontem Google w momencie\nwspierania gry przez Google Cardboard.\n\nOd tego momentu musisz zdobywać wszystkie kupony w grze.\n(zaktualizuj grę do wersji BombSquad Pro za darmo)",
"testAccountWarningOculusText": "Ostrzeżenie: zapisujesz się przy użyciu konta \"test\".\nZostanie ono zastąpione kontem oculusowym jeszcze w tym roku,\nktóre będzie oferowało zakup kuponów i inne funkcje.\n\nTeraz musisz zarobić wszystkie kupony grając.\n(jednakże możesz uzyskać aktualizację do wersji Pro za darmo)",
"testAccountWarningText": "Ostrzeżenie: możesz się zapisać używając konta \"test\".\nTo konto jest powiązane z konkretnym urządzeniem i \nmoże okresowo się zresetować. (wobec tego proszę nie\nzbierać/odblokowywać rzeczy lub osiągnięć dla tego konta)",
@ -45,7 +46,7 @@
"unlinkAccountsInstructionsText": "Wybierz konto do rozłączenia",
"unlinkAccountsText": "Rozłącz konta",
"unlinkLegacyV1AccountsText": "Rozłącz stare konta (V1)",
"v2LinkInstructionsText": "Użyj tego linku aby stworzyć konto lub zaloguj się.",
"v2LinkInstructionsText": "Użyj tego linku, aby stworzyć konto lub zaloguj się.",
"viaAccount": "(przez konto ${NAME})",
"youAreLoggedInAsText": "Jesteś zalogowany jako:",
"youAreSignedInAsText": "Jesteś zalogowany jako:"
@ -54,11 +55,11 @@
"achievementText": "Osiągnięcia",
"achievements": {
"Boom Goes the Dynamite": {
"description": "Zabij 3 złych gości używając TNT",
"descriptionComplete": "Zabiłeś 3 złych gości używając TNT",
"description": "Zabij 3 złych gości, używając TNT",
"descriptionComplete": "Zabiłeś 3 złych gości, używając TNT",
"descriptionFull": "Zabij 3 złych gości za pomocą TNT w trybie ${LEVEL}",
"descriptionFullComplete": "Zabiłeś 3 złych gości za pomocą TNT w trybie ${LEVEL}",
"name": "Uwaga Leci Dynamit"
"name": "Uwaga, Leci Dynamit"
},
"Boxer": {
"description": "Wygraj bez używania bomb",
@ -339,6 +340,8 @@
"getMoreGamesText": "Więcej rozgrywek...",
"titleText": "Dodaj grę"
},
"addToFavoritesText": "Dodaj do ulubionych",
"addedToFavoritesText": "Dodano '${NAME}' do ulubionych",
"allText": "Wszystko",
"allowText": "Zezwól",
"alreadySignedInText": "Twoje konto jest zalogowane z innego urządzenia;\nproszę zmienić konta lub zamknąć grę na innych\nurządzeniach i spróbować ponownie.",
@ -367,7 +370,7 @@
"bombText": "Bomba",
"boostText": "Dopalacz",
"bsRemoteConfigureInAppText": "${REMOTE_APP_NAME} jest konfigurowany w samej aplikacji.",
"buttonText": "Przycisk",
"buttonText": "przycisk",
"canWeDebugText": "Chcesz aby BombSquad automatycznie raportował błędy,\nawarie i podstawowe informacje o użytkowaniu deweloperowi?\n\nPrzesyłane dane nie będą zawierać Twoich osobistych danych,\na pomogą jedynie poprawić działanie gry i usunąć jej błędy.",
"cancelText": "Anuluj",
"cantConfigureDeviceText": "Wybacz ale ${DEVICE} nie jest konfigurowalne.",
@ -376,6 +379,7 @@
"chatMutedText": "Czat Wyciszony",
"chatUnMuteText": "Podgłośnij Czat",
"choosingPlayerText": "<wybieram gracza>",
"codesExplainText": "Kody są dostarczane przez dewelopera w celu\ndiagnozowania i poprawiania problemów z kontem.",
"completeThisLevelToProceedText": "Musisz ukończyć ten\netap aby kontynuować!",
"completionBonusText": "Bonusowe zakończenie",
"configControllersWindow": {
@ -392,7 +396,7 @@
},
"configGamepadSelectWindow": {
"androidNoteText": "Uwaga: wsparcie kontrolera uzależnione jest od urządzenia i wersji Androida.",
"pressAnyButtonText": "Naciśnij dowolny na kontrolerze,\nktórego chcesz skonfigurować...",
"pressAnyButtonText": "Naciśnij dowolny przycisk na kontrolerze,\nktórego chcesz skonfigurować...",
"titleText": "Skonfiguruj Kontrolery"
},
"configGamepadWindow": {
@ -400,8 +404,8 @@
"advancedTitleText": "Zaawansowane ustawienia Kontrolera",
"analogStickDeadZoneDescriptionText": "(włącz jeśli Twoja postać dryfuje po zwolnieniu drążka)",
"analogStickDeadZoneText": "Martwa strefa analogowego drążka",
"appliesToAllText": "(zastosuj dla wszystkich kontrolerów tego typu)",
"autoRecalibrateDescriptionText": "(aktywuj jeśli Twoja postać nie porusza się z pełną szybkością)",
"appliesToAllText": "(dotyczy wszystkich kontrolerów tego typu)",
"autoRecalibrateDescriptionText": "(aktywuj, jeśli Twoja postać nie porusza się z pełną szybkością)",
"autoRecalibrateText": "Auto kalibracja drążka analogowego",
"axisText": "oś",
"clearText": "wyczyść",
@ -426,7 +430,7 @@
"runButton2Text": "Uruchom przycisk 2",
"runTrigger1Text": "Uruchom spust 1",
"runTrigger2Text": "Uruchom spust 2",
"runTriggerDescriptionText": "(analogowe triggery pozwalają na uruchomione przy różnych prędkościach)",
"runTriggerDescriptionText": "(analogowe triggery pozwalają ci biec przy różnych prędkościach)",
"secondHalfText": "Użyj aby skonfigurować drugiego kontrolera,\nktóry widoczny jest jako pierwszy będąc\npodłączonym do tego samego urządzenia.",
"secondaryEnableText": "Aktywuj",
"secondaryText": "Drugi Kontroler",
@ -459,16 +463,17 @@
"titleText": "Skonfiguruj ekran dotykowy",
"touchControlsScaleText": "Skala przycisków dotykowych"
},
"configureDeviceInSystemSettingsText": "${DEVICE} może zostać skonfigurowany w ustawieniach systemu.",
"configureItNowText": "Skonfigurować teraz?",
"configureText": "Skonfiguruj",
"connectMobileDevicesWindow": {
"amazonText": "Sklep Amazon",
"appStoreText": "App Store",
"bestResultsText": "Dla lepszych efektów stwórz szybką sieć bezprzewodową.\nMożesz zredukować opóźnienia w grze poprzez: wyłączenie innych\nurządzeń korzystających w czasie gry z sieci wifi, będąc\nodpowiednio blisko routera wifi lub podpięcie się do hosta\nbezpośrednio przewodem sieciowym.",
"bestResultsText": "Dla lepszych efektów użyj szybkiej sieci bezprzewodowej. Możesz\nzredukować opóźnienia w grze poprzez wyłączenie innych urządzeń\nkorzystających w czasie gry z sieci wifi, bycie odpowiednio blisko\nroutera wifi lub podpięcie się do hosta bezpośrednio przewodem sieciowym.",
"explanationText": "Aby użyć smartfona lub tableta jako kontrolera w grze,\nzainstaluj na nim aplikację ${REMOTE_APP_NAME}. Do gry ${APP_NAME} można\nprzyłączyć dowolną ilość urządzeń poprzez sieć WiFi i to całkowicie za darmo!",
"forAndroidText": "dla Androida:",
"forIOSText": "dla iOS:",
"getItForText": "Pobierz ${REMOTE_APP_NAME} dla systemu iOS ze sklepu Apple, a \ndla systemu Android ze sklepu Google Play lub Amazon Appstore.",
"getItForText": "Pobierz ${REMOTE_APP_NAME} dla systemu iOS ze sklepu Apple, a \ndla systemu Android ze sklepu Google Play lub Amazon Appstore",
"googlePlayText": "Google Play",
"titleText": "Używanie urządzeń mobilnych jako kontrolerów:"
},
@ -502,7 +507,7 @@
"powerRankingPointsToRankedText": "(${CURRENT} z ${REMAINING} pkt)",
"powerRankingText": "Osiągnięcia",
"prizesText": "Nagrody",
"proMultInfoText": "Gracze z aktualizacją ${PRO} otrzymują\n${PERCENT}% punktów więcej.",
"proMultInfoText": "Gracze z ulepszeniem ${PRO} otrzymują\n${PERCENT}% punktów więcej.",
"seeMoreText": "Więcej...",
"skipWaitText": "Pomiń oczekiwanie",
"timeRemainingText": "Pozostały czas",
@ -529,7 +534,7 @@
"legalText": "Prawa autorskie:",
"publicDomainMusicViaText": "Podkład muzyczny - ${NAME}",
"softwareBasedOnText": "To oprogramowanie jest częściowo oparte na pracy ${NAME}",
"songCreditText": "${TITLE} wykonywana przez ${PERFORMER}.\nSkomponowana przez ${COMPOSER}. Zorganizowana przez ${ARRANGER}.\nOpublikowana przez ${PUBLISHER}.\nDzięki uprzejmości ${SOURCE}",
"songCreditText": "${TITLE} wykonywana przez ${PERFORMER}.\nSkomponowana przez ${COMPOSER}. Zorganizował ją ${ARRANGER}.\nOpublikowana przez ${PUBLISHER}, dzięki uprzejmości ${SOURCE}.",
"soundAndMusicText": "Dźwięk i muzyka:",
"soundsText": "Dźwięki (${SOURCE}):",
"specialThanksText": "Specjalne podziękowania dla:",
@ -573,12 +578,14 @@
"difficultyEasyText": "Łatwy",
"difficultyHardOnlyText": "Tylko w trudnym trybie",
"difficultyHardText": "Trudny",
"difficultyHardUnlockOnlyText": "Ten poziom może zostać odblokowany tylko w trudnym trybie.\nCzy uważasz, że posiadasz to czego wymaga?!",
"difficultyHardUnlockOnlyText": "Ten poziom może zostać odblokowany tylko w trudnym trybie.\nCzy uważasz, że posiadasz to, czego wymaga?!?!",
"directBrowserToURLText": "Proszę, otwórz przeglądarkę na podanym adresie:",
"disableRemoteAppConnectionsText": "Wyłącz łączenia aplikacji BS-Remote",
"disableXInputDescriptionText": "Pozwala na podłączenie 4 kontrolerów, ale może nie działać.",
"disableXInputText": "Wyłącz XInput",
"disabledText": "Wyłączone",
"discordFriendsText": "Chcesz poszukać nowych ludzi do gry?\nDołącz do naszego Discorda i znajdź nowych znajomych!",
"discordJoinText": "Dołącz do Discorda",
"doneText": "Gotowe",
"drawText": "Remis",
"duplicateText": "Duplikuj",
@ -616,7 +623,7 @@
"randomText": "losuj",
"titleEditText": "Edytuj profil",
"titleNewText": "Nowy profil",
"unavailableText": "\"${NAME}\" jest zajęta, spróbuj innej.",
"unavailableText": "Nazwa \"${NAME}\" jest zajęta; spróbuj innej.",
"upgradeProfileInfoText": "To zarezerwuje nazwę gracza tylko dla\nciebie i pozwoli ci dodać do niego ikonkę.",
"upgradeToGlobalProfileText": "Ulepsz do Profilu Globalnego"
},
@ -666,7 +673,7 @@
"exportSuccessText": "'${NAME}' eksportowane.",
"externalStorageText": "Pamięć zewnętrzna",
"failText": "Niepowodzenie",
"fatalErrorText": "O nie, czegoś brakuje lub jest uszkodzone.\nSpróbuj przeinstalować grę lub skontaktuj się \npoprzez ${EMAIL} dla uzyskania pomocy.",
"fatalErrorText": "O nie, czegoś brakuje lub coś jest uszkodzone.\nSpróbuj przeinstalować grę lub skontaktuj się \npoprzez ${EMAIL} dla uzyskania pomocy.",
"fileSelectorWindow": {
"titleFileFolderText": "Wybierz plik lub katalog",
"titleFileText": "Wybierz plik",
@ -711,7 +718,7 @@
"gamesToText": "${WINCOUNT} do ${LOSECOUNT}",
"gatherWindow": {
"aboutDescriptionLocalMultiplayerExtraText": "Pamiętaj: każde urządzenie podczas imprezy może posiadać\nwięcej niż jednego gracza jeśli masz więcej kontrolerów.",
"aboutDescriptionText": "Używaj tych zakładek aby zorganizować imprezę.\n\nImprezy pozwalają na organizowanie rozgrywek i\nturniejów ze znajomymi wykorzystując różne urządzenia.\n\nUżyj przycisku ${PARTY} w prawym górnym rogu aby\nrozmawiać i współdziałać podczas imprezy.\n(na kontrolerze wciśnij ${BUTTON} gdy jesteś w menu)",
"aboutDescriptionText": "Używaj tych zakładek, aby zorganizować imprezę.\n\nImprezy pozwalają na organizowanie rozgrywek i\nturniejów ze znajomymi, wykorzystując różne urządzenia.\n\nUżyj przycisku ${PARTY} w prawym górnym rogu, aby\nrozmawiać i współdziałać podczas imprezy.\n(na kontrolerze wciśnij ${BUTTON}, gdy jesteś w menu)",
"aboutText": "Info",
"addressFetchErrorText": "<błąd pobierania adresów>",
"appInviteInfoText": "Zaproś przyjaciół by wypróbowali BombSquada, a dostaną \n${COUNT} darmowych kuponów. Dostaniesz ${YOU_COUNT}\nza każdego ktory wypróbuje.",
@ -741,13 +748,13 @@
"friendPromoCodeExpireText": "Ten kod wygaśnie po ${EXPIRE_HOURS} godzinach i działa tylko dla nowych graczy.",
"friendPromoCodeInfoText": "Może zostać wykupione do ${COUNT} kuponów.\n\nIdź do \"Ustawienia->Zaawansowane->Wpisz Kod Promocyjny\" w grze aby go użyć. Idź do bombsquadgame.com by pobrać\nlinki do wszystkich wspieranych platform. Ten kod\nwygaśnie w ${EXPIRE_HOURS} godzin i jest prawidłowy tylko dla nowych graczy.",
"friendPromoCodeInstructionsText": "Aby użyć, otwórz ${APP_NAME} i idź do \"Ustawienia->Zaawansowane-> Wpisz kod\".\nWejdź na bombsquadgame.com by zobaczyć linki dla wszystkich dostępnych platform (Android itp.)",
"friendPromoCodeRedeemLongText": "Może być żądane do ${COUNT} darmowych kuponów dla najwięcej ${MAX_USES} ludzi.",
"friendPromoCodeRedeemLongText": "Wykorzystanie go daje ${COUNT} darmowych kuponów dla najwięcej ${MAX_USES} ludzi.",
"friendPromoCodeRedeemShortText": "Może być żądane do ${COUNT} kuponów w grze.",
"friendPromoCodeWhereToEnterText": "(W \"Ustawienia->Zaawansowane->Wpisz kod\")",
"getFriendInviteCodeText": "Zdobądź kod promocyjny kumpla",
"googlePlayDescriptionText": "Zaproś użytkowników Google Play na imprezę:",
"googlePlayInviteText": "Zaproś",
"googlePlayReInviteText": "Obecnie jest ${COUNT} graczy Google Play'a na imprezie,\nktórzy zostaną rozłączeni jeśli uruchomisz nowe zaproszenie.\nUwzględnij ich w nowym zaproszeniu, aby mogli powrócić.",
"googlePlayReInviteText": "Obecnie jest ${COUNT} graczy z Google Play'a na imprezie,\nktórzy zostaną rozłączeni jeśli uruchomisz nowe zaproszenie.\nUwzględnij ich w nowym zaproszeniu, aby mogli powrócić.",
"googlePlaySeeInvitesText": "Zobacz zaproszenia",
"googlePlayText": "Google Play",
"googlePlayVersionOnlyText": "(Tylko Android / Google Play)",
@ -775,11 +782,12 @@
"manualYourLocalAddressText": "Twój adres lokalny:",
"nearbyText": "W pobliżu",
"noConnectionText": "<brak połączenia>",
"noPartiesAddedText": "Nie dodano imprez",
"otherVersionsText": "(Inne wersje)",
"partyCodeText": "Kod imprezy",
"partyInviteAcceptText": "Akceptuj",
"partyInviteDeclineText": "Ignoruj",
"partyInviteGooglePlayExtraText": "(zobacz zakładkę 'Google Play' w oknie 'Punkt Zborny')",
"partyInviteGooglePlayExtraText": "(zobacz zakładkę 'Google Play' w oknie 'Zbiórka')",
"partyInviteIgnoreText": "Ignoruj",
"partyInviteText": "${NAME} zaprosił Cię abyś\ndołączył do ich imprezy.",
"partyNameText": "Nazwa Imprezy",
@ -807,7 +815,7 @@
"startHostingText": "Hostuj",
"startStopHostingMinutesText": "Możesz rozpocząć i zakończyć hostowanie za darmo przez następne ${MINUTES} minut.",
"stopHostingText": "Zakończ hostowanie",
"titleText": "Punkt Zborny",
"titleText": "Zbiórka",
"wifiDirectDescriptionBottomText": "Jeśli wszystkie urządzenia posiadają panel 'Wi-Fi Direct', to powinny użyć go aby\nodnaleźć i połączyć się między sobą. Kiedy wszystkie są już połączone, możesz utworzyć\nimprezę używając zakładki 'Lokalna sieć', tak samo jak w standardowej sieci Wi-Fi.\n\nDla optymalnego działania, host Wi-Fi Direct powinien być hostem imprezy w ${APP_NAME}.",
"wifiDirectDescriptionTopText": "Wi-Fi Direct może być używany do bezpośredniego łączenia urządzeń na\nAndroidzie bez konieczności stosowania sieci Wi-Fi. Najlepiej działa na\nurządzeniach z systemem Android 4.2 lub nowszym.\nAby go użyć, otwórz ustawienia Wi-Fi urządzenia i odszukaj 'Wi-Fi Direct'.",
"wifiDirectOpenWiFiSettingsText": "Otwórz ustawienia Wi-Fi",
@ -824,7 +832,7 @@
"titleText": "Zdobądź monety"
},
"getTicketsWindow": {
"freeText": "DARMOWE!",
"freeText": "ZA DARMO!",
"freeTicketsText": "Darmowe kupony",
"inProgressText": "Transakcja w toku; proszę spróbować za chwilkę.",
"purchasesRestoredText": "Zakupy przywrócone.",
@ -834,7 +842,7 @@
"ticketPack1Text": "Mała paczka kuponów",
"ticketPack2Text": "Średnia paczka kuponów",
"ticketPack3Text": "Duża paczka kuponów",
"ticketPack4Text": "Paczka Kolos kuponów",
"ticketPack4Text": "Kolosalna paczka kuponów",
"ticketPack5Text": "Mamucia paczka kuponów",
"ticketPack6Text": "Paczka Ultimate kuponów",
"ticketsFromASponsorText": "Obejrzyj reklamę\ndla ${COUNT} kuponów",
@ -855,10 +863,12 @@
"alwaysText": "Zawsze",
"fullScreenCmdText": "Pełny ekran (Cmd-F)",
"fullScreenCtrlText": "Pełny ekran (Ctrl+F)",
"fullScreenText": "Pełny ekran",
"gammaText": "Gamma",
"highText": "Wysokie",
"higherText": "Max",
"lowText": "Niskie",
"maxFPSText": "Maks FPS",
"mediumText": "Średnie",
"neverText": "Nigdy",
"resolutionText": "Rozdzielczość",
@ -872,7 +882,7 @@
"helpWindow": {
"bombInfoText": "- Bomba -\nSilniejsza niż ciosy, lecz\nz powodu obrażeń może Cię\nwpędzić do grobu. Dla\nlepszego efektu wyrzuć ją przed\nwypaleniem się lontu.",
"canHelpText": "${APP_NAME} może Ci w tym pomóc",
"controllersInfoText": "Możesz zagrać w ${APP_NAME} ze znajomymi poprzez sieć lub na tym\nsamym urządzeniu jeśli masz wystarczająco dużo kontrolerów.\n${APP_NAME} obsługuje wiele z nich; możesz nawet użyć smartfonów\njako kontrolery wykorzystując aplikację '${REMOTE_APP_NAME}'.\nZobacz Ustawienia->Kontrolery, aby uzyskać szczegółowe informacje",
"controllersInfoText": "Możesz zagrać w ${APP_NAME} ze znajomymi poprzez sieć lub na tym\nsamym urządzeniu, jeśli masz wystarczająco dużo kontrolerów.\n${APP_NAME} obsługuje wiele z nich; możesz nawet użyć smartfonów\njako kontrolery, wykorzystując aplikację '${REMOTE_APP_NAME}'.\nZobacz Ustawienia->Kontrolery, aby uzyskać szczegółowe informacje.",
"controllersInfoTextFantasia": "Gracz może używać zdalnego kontrolera, jednak zalecane są\ngamepady. Możesz także użyć urządzeń mobilnych jako kontrolerów\ngry za pomocą darmowej aplikacji 'BombSquad Remote'.\nSprawdź informacje dostępne w ustawieniach kontrolerów.",
"controllersInfoTextMac": "Jeden lub dwóch graczy może używać klawiatury, jednak najlepiej korzystać z\ngamepadów. Gra obsługuje pady USB, kontrolery PS3, Xbox360, Wiimote i urządzenia\nz systemem iOS/Android. Na pewno coś z tego posiadasz aby sterować postaciami?\nWięcej informacji dostępnych jest w ustawieniach kontrolerów.",
"controllersInfoTextOuya": "Do gry w BombSquad możesz wykorzystać kontrolery OUYA, PS3, Xbox360\ni wiele innych gamepadów podłączanych za pomocą USB lub Bluetootha.\nMożesz również używać jako kontrolery urządzenia z systemami iOS/Android\nz pomocą darmowej aplikacji 'BombSquad Remote'. Więcej informacji w\nustawieniach kontrolerów.",
@ -880,7 +890,7 @@
"controllersText": "Kontrolery",
"controlsSubtitleText": "Twoja postać w ${APP_NAME} posiada kilka podstawowych umiejętności:",
"controlsText": "Przyciski",
"devicesInfoText": "Wersja VR ${APP_NAME} może być używana w rozgrywce sieciowej wraz z\nwersją regularną, więc wbijaj do gry ze swoimi telefonami, tabletami\ni komputerami do rozgrywki. Wersja regularna gry może być również\nwykorzystana do przyłączenia się zainteresowanych do wersji VR aby\npokazać jak wygląda rozgrywka.",
"devicesInfoText": "Wersja VR ${APP_NAME} może być używana w rozgrywce sieciowej wraz z\nwersją regularną, więc wyciągaj swoje dodatkowe telefony, tablety\noraz komputery i wbijaj do gry. Regularną wersję gry można nawet\nużyć do połączenia się z wersją VR tylko po to, aby umożliwić\nludziom z zewnątrz oglądanie tej akcji.",
"devicesText": "Urządzenia",
"friendsGoodText": "Dobrze ich mieć. ${APP_NAME} sprawia największą frajdę\nz kilkoma graczami. Gra może obsłużyć do 8 graczy jednocześnie.",
"friendsText": "Znajomych",
@ -1105,8 +1115,10 @@
"noExternalStorageErrorText": "Brak pamięci zewnętrznej w tym urządzeniu",
"noGameCircleText": "Błąd: niezalogowany w GameCircle",
"noJoinCoopMidwayText": "Rozgrywki trybu Kooperacji nie mogą być łączone w czasie ich trwania.",
"noPluginsInstalledText": "Brak zainstalowanych pluginów",
"noProfilesErrorText": "Nie masz własnego profilu gracza, dlatego nazwano Cię: '${NAME}'.\nPrzejdź do Ustawień->Profile Gracza aby stworzyć własny.",
"noScoresYetText": "Brak wyników do tej pory.",
"noServersFoundText": "Nie znaleziono serwerów.",
"noThanksText": "Nie, dziękuję",
"noTournamentsInTestBuildText": "OSTRZEŻENIE: Wyniki turniejów z tej wersji testowej będą ignorowane.",
"noValidMapsErrorText": "Nie znaleziono żadnych map dla tego typu rozgrywki.",
@ -1119,9 +1131,9 @@
"notUsingAccountText": "Uwaga: ignorowanie konta ${SERVICE}.\nIdź do \"Konto -> Zaloguj się kontem ${SERVICE}\", jeżeli chcesz go używać.",
"nothingIsSelectedErrorText": "Nic nie zaznaczyłeś!",
"numberText": "#${NUMBER}",
"offText": "Off",
"offText": "Wył.",
"okText": "Ok",
"onText": "On",
"onText": "Wł.",
"oneMomentText": "Chwileczkę...",
"onslaughtRespawnText": "${PLAYER} odrodzi się w fali ${WAVE}",
"orText": "${A} lub ${B}",
@ -1188,17 +1200,17 @@
"pluginsRemovedText": "Usunięto ${NUM} pluginy(ów)",
"pluginsText": "Pluginy",
"practiceText": "Praktyka",
"pressAnyButtonPlayAgainText": "Naciśnij dowolny przycisk aby zagrać ponownie...",
"pressAnyButtonText": "Naciśnij dowolny przycisk aby kontynuować...",
"pressAnyButtonToJoinText": "naciśnij dowolny przycisk aby dołączyć...",
"pressAnyKeyButtonPlayAgainText": "Naciśnij dowolny klawisz/przycisk aby zagrać ponownie...",
"pressAnyKeyButtonText": "Naciśnij dowolny klawisz/przycisk aby kontynuować...",
"pressAnyButtonPlayAgainText": "Naciśnij dowolny przycisk, aby zagrać ponownie...",
"pressAnyButtonText": "Naciśnij dowolny przycisk, aby kontynuować...",
"pressAnyButtonToJoinText": "naciśnij dowolny przycisk, aby dołączyć...",
"pressAnyKeyButtonPlayAgainText": "Naciśnij dowolny klawisz/przycisk, aby zagrać ponownie...",
"pressAnyKeyButtonText": "Naciśnij dowolny klawisz/przycisk, aby kontynuować...",
"pressAnyKeyText": "Naciśnij dowolny klawisz...",
"pressJumpToFlyText": "** Naciśnij wielokrotnie skok aby polecieć **",
"pressPunchToJoinText": "naciśnij CIOS aby dołączyć...",
"pressToOverrideCharacterText": "naciśnij ${BUTTONS} aby zastąpić swoją postać",
"pressToSelectProfileText": "naciśnij ${BUTTONS} aby wybrać gracza.",
"pressToSelectTeamText": "naciśnij ${BUTTONS} aby wybrać drużynę.",
"pressJumpToFlyText": "** Naciskaj wielokrotnie skok, aby polecieć **",
"pressPunchToJoinText": "naciśnij CIOS, aby dołączyć...",
"pressToOverrideCharacterText": "naciśnij ${BUTTONS}, aby zastąpić swoją postać",
"pressToSelectProfileText": "naciśnij ${BUTTONS}, aby wybrać gracza",
"pressToSelectTeamText": "naciśnij ${BUTTONS}, aby wybrać drużynę",
"profileInfoText": "Stwórz profile dla siebie i swoich znajomych\ndostosowując ich nazwy i kolory postaci.",
"promoCodeWindow": {
"codeText": "Kod",
@ -1209,7 +1221,7 @@
"ps3ControllersWindow": {
"macInstructionsText": "Wyłącz zasilanie konsoli PS3, upewnij się, że masz uruchomiony\nBluetooth w swoim Mac'u, następnie podłącz kontroler do portu\nUSB Mac'a aby sparować urządzenia. Od teraz można używać na\nkontrolerze przycisku 'home' aby podłączyć go do Mac'a w obu\ntrybach - przewodowym (USB) i bezprzewodowym (Bluetooth).\n\nNa niektórych Mac'ach trzeba podać kod aby urządzenia sparować.\nJeśli się tak stanie poszukaj poradnika na google.\n\n\n\n\nKontrolery PS3 podłączone bezprzewodowo powinny być widoczne na\nliście urządzeń w Preferencjach Systemu->Bluetooth. Być może\ntrzeba będzie je usunąć z tej listy, kiedy zechcesz korzystać\nz nich ponownie w PS3.\n\nPamiętaj aby rozłączyć je z Bluetootha kiedy nie będą używane\nponieważ wyładują się ich baterie.\n\nBluetooth powinien obsłużyć do 7 podłączonych urządzeń, chociaż\nliczba ta może się wahać.",
"macInstructionsTextScale": 0.74,
"ouyaInstructionsText": "Aby używać kontrolerów PS3 z konsolą OUYA, po prostu podłącz je kablem USB\naby sparować urządzenia. Może to spowodować rozłączenie innych kontrolerów,\nwięc powinieneś później uruchomić ponownie konsolę OUYA i odłączyć kabel USB.\n\nOd teraz powinien być aktywny przycisk HOME aby połączyć się bezprzewodowo. Kiedy zakończysz grę, przytrzymaj HOME przez 10 sekund aby wyłączyć kontroler;\nw przeciwnym razie może on wyczerpać jego baterie.",
"ouyaInstructionsText": "Aby używać kontrolera PS3 z konsolą OUYA, po prostu podłącz go kablem USB,\naby go sparować. Może to spowodować rozłączenie innych kontrolerów,\nwięc powinieneś później uruchomić ponownie konsolę OUYA i odłączyć kabel USB.\n\nOd teraz powinien być aktywny przycisk HOME, aby połączyć się bezprzewodowo.\nKiedy zakończysz grę, przytrzymaj HOME przez 10 sekund, aby wyłączyć kontroler;\nw przeciwnym razie może on wyczerpać jego baterie.",
"ouyaInstructionsTextScale": 0.74,
"pairingTutorialText": "poradnik video parowania kontrolerów",
"titleText": "Korzystanie z kontrolerów PS3 w ${APP_NAME}:"
@ -1218,7 +1230,7 @@
"punchBoldText": "CIOS",
"punchText": "Cios",
"purchaseForText": "Kup za ${PRICE}",
"purchaseGameText": "Zakup Grę",
"purchaseGameText": "Kup Grę",
"purchasingText": "Kupowanie...",
"quitGameText": "Wyjść z ${APP_NAME}?",
"quittingIn5SecondsText": "Wyjście za 5 sekund...",
@ -1260,7 +1272,7 @@
"start": "Start",
"version_mismatch": "Wersje nie pasują.\nSprawdź czy BombSquad i BombSquad Remote\nmają najnowszą wersję i spróbuj ponownie."
},
"removeInGameAdsText": "Odblokowywując wersję \"${PRO}\" pozbędziesz się reklam w grze.",
"removeInGameAdsText": "Odblokowując wersję \"${PRO}\", pozbędziesz się reklam w grze.",
"renameText": "Zmień nazwę",
"replayEndText": "Zakończ powtórkę",
"replayNameDefaultText": "Ostatnia powtórka",
@ -1282,7 +1294,9 @@
"runBoldText": "URUCHOM",
"runText": "Uruchom",
"saveText": "Zapisz",
"scanScriptsErrorText": "Błąd w skanowaniu skryptów; Sprawdź konsolę dla szczegółów",
"scanScriptsErrorText": "Błąd w skanowaniu skryptów. Sprawdź konsolę dla szczegółów.",
"scanScriptsMultipleModulesNeedUpdatesText": "${PATH} oraz ${NUM} innych modułów potrzebują aktualizacji do api ${API}.",
"scanScriptsSingleModuleNeedsUpdatesText": "${PATH} potrzebuje aktualizacji do api ${API}.",
"scoreChallengesText": "Wyzwania Punktowe",
"scoreListUnavailableText": "Lista wyników niedostępna.",
"scoreText": "Wynik",
@ -1312,14 +1326,14 @@
"alwaysUseInternalKeyboardText": "Zawsze używaj wewn. klawiatury",
"benchmarksText": "Benchmarki & Testy Wydajności",
"disableCameraGyroscopeMotionText": "Wyłącz Kontrolę Kamery Żyroskopem",
"disableCameraShakeText": "Wyłącz Trzęsącą Kamerę",
"disableCameraShakeText": "Wyłącz trzęsienie kamery",
"disableThisNotice": "(możesz wyłączyć to powiadomienie w ustawieniach zaawansowanych)",
"enablePackageModsDescriptionText": "(aktywuje dodatkowe możliwości modowania ale wyłącza grę sieciową)",
"enablePackageModsText": "Włącz lokalne pakiety modów",
"enterPromoCodeText": "Wpisz kod",
"forTestingText": "Uwaga: wartości stosowane do testów będą utracone po wyjściu z gry.",
"helpTranslateText": "Tłumaczenia ${APP_NAME} na inne języki są wysiłkiem społeczności\nfanów tej gry. Jeśli chcesz przyczynić się lub poprawić istniejące\nbłędy w tłumaczeniu, kliknij w poniższy link. Z góry dziękuję!",
"kickIdlePlayersText": "Wyrzuć nieaktywnych graczy",
"kickIdlePlayersText": "Wyrzucaj nieaktywnych graczy",
"kidFriendlyModeText": "Tryb dla dzieciaków (zredukowana przemoc itd.)",
"languageText": "Język",
"moddingGuideText": "Przewodnik modowania gry",
@ -1327,6 +1341,7 @@
"netTestingText": "Testowanie sieci",
"resetText": "Reset",
"showBombTrajectoriesText": "Pokaż trajektorię bomb",
"showDevConsoleButtonText": "Pokaż przycisk konsoli deweloperskiej",
"showInGamePingText": "Pokaż ping w grze",
"showPlayerNamesText": "Pokazuj nazwy graczy",
"showUserModsText": "Pokaż katalog modów",
@ -1334,7 +1349,7 @@
"translationEditorButtonText": "Edytor tłumaczeń ${APP_NAME}",
"translationFetchErrorText": "status tłumaczenia niedostępny",
"translationFetchingStatusText": "sprawdzanie statusu tłumaczenia...",
"translationInformMe": "Powiadom mnie gdy mój język będzie potrzebował uaktualnienia",
"translationInformMe": "Powiadom mnie, gdy mój język będzie potrzebował uaktualnienia",
"translationNoUpdateNeededText": "Obecnie używany język jest aktualny; ekstra!",
"translationUpdateNeededText": "** obecnie używany język wymaga jego zaktualizowania! **",
"vrTestingText": "Testowanie VR"
@ -1422,6 +1437,8 @@
"storeText": "Sklep",
"submitText": "Prześlij",
"submittingPromoCodeText": "Przesyłanie Kodu...",
"successText": "Sukces!",
"supportEmailText": "Jeśli doświadczasz jakichś problemów z\naplikacją, wyślij e-maila na ${EMAIL}.",
"teamNamesColorText": "Nazwy Drużyn/Kolory...",
"teamsText": "Gra Zespołowa",
"telnetAccessGrantedText": "Dostęp telnet włączony.",
@ -1433,7 +1450,7 @@
"thankYouText": "Dziękuję za Twoje wsparcie! Miłej gry!",
"threeKillText": "POTRÓJNE ZABÓJSTWO!!",
"timeBonusText": "Bonus czasowy",
"timeElapsedText": "Czas upłynął",
"timeElapsedText": "Czas, jaki upłynął",
"timeExpiredText": "Czas minął",
"timeSuffixDaysText": "${COUNT}d",
"timeSuffixHoursText": "${COUNT}h",
@ -1461,7 +1478,7 @@
"Butch": "Butch",
"Easter Bunny": "Zajączek Wielkanocny",
"Flopsy": "Flopsy",
"Frosty": "Frosty",
"Frosty": "Mrozek",
"Gretel": "Małgosia",
"Grumbledorf": "Grumbledorf",
"Jack Morgan": "Jack Morgan",
@ -1504,11 +1521,11 @@
"Infinite Onslaught": "Nieskończony Atak",
"Infinite Runaround": "Nieskończone Otaczanie",
"Onslaught": "Nieskończony Atak",
"Onslaught Training": "Atakujący Trening",
"Pro ${GAME}": "Zawodowy tryb ${GAME}",
"Pro Football": "Zawodowy Futbol",
"Pro Onslaught": "Atak Zawodowca",
"Pro Runaround": "Zawodowe Otaczanie",
"Onslaught Training": "Treningowy Atak",
"Pro ${GAME}": "Cięższy tryb ${GAME}",
"Pro Football": "Cięższy Futbol",
"Pro Onslaught": "Cięższy Atak",
"Pro Runaround": "Cięższe Otaczanie",
"Rookie ${GAME}": "Rekrucki tryb ${GAME}",
"Rookie Football": "Futbol Rekruta",
"Rookie Onslaught": "Atak Rekruta",
@ -1520,7 +1537,7 @@
"Uber Runaround": "Super Otaczanie"
},
"gameDescriptions": {
"Be the chosen one for a length of time to win.\nKill the chosen one to become it.": "Bądź wybrańcem przez określony czas aby wygrać.\nZabij wybrańca aby się nim stać.",
"Be the chosen one for a length of time to win.\nKill the chosen one to become it.": "Bądź wybrańcem przez określony czas, aby wygrać.\nZabij wybrańca, aby się nim stać.",
"Bomb as many targets as you can.": "Zbombarduj tyle celów, ile tylko możesz.",
"Carry the flag for ${ARG1} seconds.": "Utrzymaj flagę przez ${ARG1} sekund.",
"Carry the flag for a set length of time.": "Utrzymaj flagę przez określony czas.",
@ -1689,7 +1706,7 @@
"An error has occurred; please contact support. (${ERROR})": "Wystąpił błąd; skontaktuj się z pomocą techniczną. (${ERROR})",
"An error has occurred; please contact support@froemling.net.": "Wystąpił błąd; skontaktuj się z support@froemling.net.",
"An error has occurred; please try again later.": "Wystąpił błąd; spróbuj ponownie później.",
"Are you sure you want to link these accounts?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nThis cannot be undone!": "Na pewno chcesz połączyć te konta?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nUwaga: To nie może być cofnięte!",
"Are you sure you want to link these accounts?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nThis cannot be undone!": "Na pewno chcesz połączyć te konta?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nNie da się tego cofnąć!",
"BombSquad Pro unlocked!": "BombSquad Pro odblokowane!",
"Can't link 2 accounts of this type.": "Nie można połączyć dwóch kont tego typu.",
"Can't link 2 diamond league accounts.": "Nie można połączyć dwóch kont w diamentowej lidze.",
@ -1706,7 +1723,7 @@
"Item unlocked!": "Przedmiot odblokowany!",
"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)": "ŁĄCZENIE ODRZUCONE. ${ACCOUNT} zawiera\nznaczący postęp który zostałby USUNIĘTY.\nMożesz połączyć konta na odwrót jeśli chcesz\n(i stracić postęp Z TEGO konta).",
"Link account ${ACCOUNT} to this account?\nAll existing data on ${ACCOUNT} will be lost.\nThis can not be undone. Are you sure?": "Połączyć konto ${ACCOUNT} z tym kontem?\nCały postęp z konta ${ACCOUNT} będzie stracony.\nNie można tego odwrócić. Pewna decyzja?",
"Max number of playlists reached.": "Osiągnięto maksymalną ilość playlist.",
"Max number of playlists reached.": "Osiągnięto maksymalną liczbę playlist.",
"Max number of profiles reached.": "Osiągnięto maksymalną liczbę profili.",
"Maximum friend code rewards reached.": "Osiągnięto limit kodów promocyjnych.",
"Message is too long.": "Wiadomość jest za długa.",
@ -1731,7 +1748,7 @@
"Tournaments require ${VERSION} or newer": "Turnieje potrzebują ${VERSION} albo nowszej",
"Unlink ${ACCOUNT} from this account?\nAll data on ${ACCOUNT} will be reset.\n(except for achievements in some cases)": "Rozłączyć konto ${ACCOUNT} z tego konta?\nCały postęp z konta ${ACCOUNT} zostanie zresetowany.\n(oprócz osiągnięć w niektórych przypadkach)",
"WARNING: complaints of hacking have been issued against your account.\nAccounts found to be hacking will be banned. Please play fair.": "OSTRZEŻENIE: przeciwko Tobie zostały złożone skargi o oszukiwanie.\nKonta ludzi oszukujących zostaną zablokowane. Proszę grać uczciwie.",
"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": "Chcesz połączyć swoje konto z urządzenia z tym?\n\nTwoje konto urządzenia to ${ACCOUNT1}\nTo konto to ${ACCOUNT2}\n\nTo pozwoli Ci zapisać istniejący postęp.\nUwaga: To nie może zostać cofnięte!!!",
"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": "Chcesz połączyć swoje konto z urządzenia z tym?\n\nTwoje konto urządzenia to ${ACCOUNT1}\nTo konto to ${ACCOUNT2}\n\nTo pozwoli Ci zapisać istniejący postęp.\nUwaga: Nie da się tego cofnąć!",
"You already own this!": "Już to posiadasz!",
"You can join in ${COUNT} seconds.": "Możesz dołączyć w ciągu ${COUNT} sekund.",
"You don't have enough tickets for this!": "Nie masz wystarczająco dużo kuponów!",
@ -1743,7 +1760,7 @@
"You must update to the newest version of the game to do this.": "Musisz zaktualizować grę do nowej wersji aby to zrobić.",
"You must wait a few seconds before entering a new code.": "Musisz odczekać kilka sekund zanim wpiszesz nowy kod.",
"You ranked #${RANK} in the last tournament. Thanks for playing!": "Zostałeś sklasyfikowany na ${RANK} pozycji w ostatnim turnieju. Dzięki za udział!",
"Your account was rejected. Are you signed in?": "Twoje Konto Zostało Odrzucone. Jesteś Zalogowany?",
"Your account was rejected. Are you signed in?": "Twoje konto zostało odrzucone. Czy jesteś zalogowany?",
"Your copy of the game has been modified.\nPlease revert any changes and try again.": "Twoja kopia gry została zmodyfikowana.\nCofnij zmiany i spróbuj ponownie.",
"Your friend code was used by ${ACCOUNT}": "Kod kumpla został użyty przez ${ACCOUNT}"
},
@ -1801,37 +1818,37 @@
},
"tips": {
"A perfectly timed running-jumping-spin-punch can kill in a single hit\nand earn you lifelong respect from your friends.": "Perfekcyjne w czasie wykonanie biegu, skoku, obrotu i uderzenia\nmoże zabić jednym ruchem wzbudzając respekt wśród znajomych.",
"Always remember to floss.": "Pamiętaj żeby nitkować zęby.",
"Always remember to floss.": "Pamiętaj, żeby nitkować zęby.",
"Create player profiles for yourself and your friends with\nyour preferred names and appearances instead of using random ones.": "Stwórz takie profile gracza (nazwa i wygląd) dla siebie i znajomych, które\nbędą Wam najbardziej odpowiadać zamiast tych losowo dobieranych.",
"Curse boxes turn you into a ticking time bomb.\nThe only cure is to quickly grab a health-pack.": "Pudła z Klątwą zamienią Cię w tykającą bombę.\nJedynym ratunkiem jest wtedy szybkie zdobycie apteczki.",
"Despite their looks, all characters' abilities are identical,\nso just pick whichever one you most closely resemble.": "Pomimo różnego wyglądu, postacie posiadają te same umiejętności, więc ma\non tylko znaczenie wizualne. Wobec tego dobierz taki, który Ci odpowiada.",
"Don't get too cocky with that energy shield; you can still get yourself thrown off a cliff.": "Nie bądź zbyt pewny siebie mając tarczę energetyczną; wciąż ktoś może Cię zrzucić z klifu.",
"Don't run all the time. Really. You will fall off cliffs.": "Nie biegaj cały czas, bo spadniesz z klifu.",
"Don't spin for too long; you'll become dizzy and fall.": "Nie obracaj się za długo; zakręci ci się w głowie i się wywrócisz.",
"Hold any button to run. (Trigger buttons work well if you have them)": "Przytrzymaj dowolny przycisk aby biec. (Triggery działają równie\ndobrze (jeśli je masz)).",
"Hold any button to run. (Trigger buttons work well if you have them)": "Przytrzymaj dowolny przycisk, aby biec. (Triggery działają równie dobrze, jeśli je masz).",
"Hold down any button to run. You'll get places faster\nbut won't turn very well, so watch out for cliffs.": "Przytrzymaj dowolny przycisk aby biec. Wówczas osiągniesz szybciej\nswój cel lecz biegnąc ciężko się skręca, więc uważaj aby nie spaść.",
"Ice bombs are not very powerful, but they freeze\nwhoever they hit, leaving them vulnerable to shattering.": "Lodowe bomby nie są potężne, ale potrafią zamrozić każdego kto\nbędzie w ich polu rażenia, wówczas będzie on podatny na skruszenie.",
"If someone picks you up, punch them and they'll let go.\nThis works in real life too.": "Jeśli ktoś Cię podniesie, uderz go wówczas Cię puści.\nSkutkuje to również w prawdziwym życiu ;)",
"If someone picks you up, punch them and they'll let go.\nThis works in real life too.": "Jeśli ktoś Cię podniesie, uderz go wówczas Cię puści.\nDziała to również w prawdziwym życiu ;)",
"If you are short on controllers, install the '${REMOTE_APP_NAME}' app\non your mobile devices to use them as controllers.": "Jeśli brakuje Ci kontrolerów, zainstaluj aplikację '${REMOTE_APP_NAME}'\nna swoich urządzeniach, aby użyć ich jako kontrolerów.",
"If you are short on controllers, install the 'BombSquad Remote' app\non your iOS or Android devices to use them as controllers.": "Jeśli brakuje Ci kontrolerów do gry, zainstaluj 'BombSquad Remote'\ndostępny w odpowiednich sklepach dla urządzeń iOS/Android.\nUżyj telefonów i tabletów jako kontrolerów do gry.",
"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.": "Jeśli przyklei się do Ciebie bomba przylepna, skacz i kręć się szalenie, to może ją\nzrzucisz. Jeżeli Ci się nie uda, wówczas twoje ostatnie chwile będą przezabawne ;).",
"If you kill an enemy in one hit you get double points for it.": "Jeśli zabijesz wroga jednym uderzeniem, otrzymasz podwójne punkty.",
"If you pick up a curse, your only hope for survival is to\nfind a health powerup in the next few seconds.": "Jeśli zbierzesz 'Klątwę', to jedyną nadzieją aby\nprzetrwać jest szybkie zebranie apteczki.",
"If you stay in one place, you're toast. Run and dodge to survive..": "Jeśli będziesz się czaił w jednym miejscu to jesteś usmażony.\nBiegaj i unikaj ataków aby przetrwać.",
"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.": "Jeśli doświadczasz dużej rotacji wśród graczy, najlepiej włącz 'auto wyrzucanie\nbezczynnych graczy' w ustawieniach. Wyrzuci to tych, którzy nie grają a jedynie\nwiszą w grze blokując nowych chcących zagrać.",
"If you pick up a curse, your only hope for survival is to\nfind a health powerup in the next few seconds.": "Jeśli zbierzesz 'Klątwę', to jedyną nadzieją, aby\nprzetrwać, jest szybkie zebranie apteczki.",
"If you stay in one place, you're toast. Run and dodge to survive..": "Jeśli będziesz stał w jednym miejscu, to staniesz się tostem. Biegaj i unikaj ataków, aby przetrwać..",
"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.": "Jeśli doświadczasz dużej rotacji wśród graczy, włącz 'Wyrzucaj nieaktywnych graczy'\nw ustawieniach, a wszyscy, co zapomnieli wyjść z gry, magicznie znikną.",
"If your device gets too warm or you'd like to conserve battery power,\nturn down \"Visuals\" or \"Resolution\" in Settings->Graphics": "Jeśli Twoje urządzenie mocno się przegrzewa lub po prostu chcesz oszczędzić baterię,\nwyłącz 'Wizualizacje' lub zmniejsz 'Rozdzielczość' w Ustawienia->Grafika",
"If your framerate is choppy, try turning down resolution\nor visuals in the game's graphics settings.": "Jeśli ilość klatek na sekundę jest zbyt niska, spróbuj\nzmniejszyć rozdzielczość lub jakość ustawień graficznych.",
"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.": "W trybie 'Przechwycenia Flagi', Twoja flaga musi znajdować się w bazie aby zapunktować.\nJeśli drugi zespół zamierza zdobyć punkt, przechwycenie ich flagi będzie dobrym\nrozwiązaniem aby ich powstrzymać.",
"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.": "W 'Przechwyceniu Flagi' wasza flaga musi znajdować się w waszej bazie, aby zapunktować. Jeśli drugi\nzespół zamierza zdobyć punkt, przechwycenie ich flagi może być dobrym rozwiązaniem, aby ich powstrzymać.",
"In hockey, you'll maintain more speed if you turn gradually.": "Grając w hokeja, większą prędkość utrzymywać będziesz przy\nstopniowym i delikatnym skręcaniu postacią.",
"It's easier to win with a friend or two helping.": "Łatwiej zwyciężyć grając w zespole z jednym lub kilkoma\ntowarzyszami broni.",
"It's easier to win with a friend or two helping.": "Łatwiej zwyciężyć, grając w zespole z jednym lub kilkoma towarzyszami broni.",
"Jump just as you're throwing to get bombs up to the highest levels.": "Dzięki podskokowi przy wyrzucaniu bomby można je wrzucić\nna wyższe, ciężko dostępne poziomy mapy.",
"Land-mines are a good way to stop speedy enemies.": "Miny lądowe są dobrym rozwiązaniem aby powstrzymywać\nszybkich i wściekłych wrogów.",
"Land-mines are a good way to stop speedy enemies.": "Miny lądowe idealnie zatrzymują szybkich i wściekłych wrogów.",
"Many things can be picked up and thrown, including other players. Tossing\nyour enemies off cliffs can be an effective and emotionally fulfilling strategy.": "Można podnosić i rzucać wieloma rzeczami, włącznie z graczami. Zrzucanie\nwrogów z klifów może być skuteczne, a taka strategia satysfakcjonująca.",
"No, you can't get up on the ledge. You have to throw bombs.": "Nie, nie dostaniesz się na wyższe półki. Może rzuć na nie bomby? :)",
"Players can join and leave in the middle of most games,\nand you can also plug and unplug controllers on the fly.": "Gracze mogą dołączyć/opuścić grę w trakcie jej trwania,\na Ty możesz dołączać/odłączać kontrolery w locie.",
"Players can join and leave in the middle of most games,\nand you can also plug and unplug gamepads on the fly.": "Gracze mogą się dołączać/opuszczać grę w trakcie większości\nrozgrywek, tak samo można w locie podłączać/rozłączać gamepady.",
"Powerups only have time limits in co-op games.\nIn teams and free-for-all they're yours until you die.": "Bonusy mają czasowe limity jedynie w rozgrywkach trybu Kooperacji.\nW rozgrywkach drużynowych i Free-for-All są Twoje aż do śmierci.",
"Practice using your momentum to throw bombs more accurately.": "Poćwicz wyczucie tempa aby rzucać bombami dokładniej.",
"Practice using your momentum to throw bombs more accurately.": "Poćwicz wyczucie tempa, aby rzucać bombami dokładniej.",
"Punches do more damage the faster your fists are moving,\nso try running, jumping, and spinning like crazy.": "Ciosy powodują większe obrażenia jeśli się energicznie porusza\npięściami, więc staraj się biegać, skakać i kręcić jak szalony.",
"Run back and forth before throwing a bomb\nto 'whiplash' it and throw it farther.": "Podbiegnij do tyłu i przed rzuceniem bomby znów\ndo przodu. Pozwoli to na jej dalsze wyrzucenie.",
"Take out a group of enemies by\nsetting off a bomb near a TNT box.": "Pozbądź się grupy wrogów poprzez\nrzucenie bomby blisko skrzyni TNT.",
@ -1840,14 +1857,14 @@
"Throw strength is based on the direction you are holding.\nTo toss something gently in front of you, don't hold any direction.": "Siła rzutu zależy od kierunku, który trzymasz. Aby delikatnie tylko\ncoś podrzucić przed sobą, nie trzymaj żadnego klawisza kierunku.",
"Tired of the soundtrack? Replace it with your own!\nSee Settings->Audio->Soundtrack": "Zmęczony domyślną ścieżką dźwiękową? Zamień ją na swoją!\nZobacz Ustawienia->Audio->Ścieżka dźwiękowa",
"Try 'Cooking off' bombs for a second or two before throwing them.": "Przytrzymaj 'odpaloną bombę' przez 1 lub 2 sekundy zanim ją rzucisz.",
"Try tricking enemies into killing eachother or running off cliffs.": "Spróbuj oszukać wrogów aby się wzajemnie pozabijali lub zrzucili z klifów.",
"Try tricking enemies into killing eachother or running off cliffs.": "Spróbuj oszukać wrogów, aby się wzajemnie pozabijali lub zrzucili z klifów.",
"Use the pick-up button to grab the flag < ${PICKUP} >": "Użyj przycisku 'Podnieś' aby chwycić flagę < ${PICKUP} >",
"Whip back and forth to get more distance on your throws..": "Cofnij się... i do przodu, aby uzyskać dalsze rzuty...",
"You can 'aim' your punches by spinning left or right.\nThis is useful for knocking bad guys off edges or scoring in hockey.": "Możesz wycelować swoje uderzenia obracając się w lewo lub prawo.\nJest to przydatne do spychania wrogów poza krawędzie lub w hokeju.",
"You can judge when a bomb is going to explode based on the\ncolor of sparks from its fuse: yellow..orange..red..BOOM.": "Możesz sam kontrolować i określić czas kiedy bomba eksploduje\npo kolorze iskier na jej loncie: żółty.. pomarańczowy.. czerwony.. BUM!",
"You can throw bombs higher if you jump just before throwing.": "Możesz rzucać bombami wyżej jeśli podskoczysz przed wyrzuceniem.",
"You don't need to edit your profile to change characters; Just press the top\nbutton (pick-up) when joining a game to override your default.": "Nie musisz edytować swojego profilu aby zmienić postacie. Naciśnij górny\nprzycisk (podnoszenie) kiedy dołączasz do gry aby zamienić domyślną postać.",
"You take damage when you whack your head on things,\nso try to not whack your head on things.": "Przyjmujesz obrażenia jeśli uderzasz głową w różne\nrzeczy, więc staraj się tego nie robić.",
"You take damage when you whack your head on things,\nso try to not whack your head on things.": "Przyjmujesz obrażenia, jeśli uderzasz głową w różne\nrzeczy, więc staraj się tego nie robić.",
"Your punches do much more damage if you are running or spinning.": "Twoje ciosy zadadzą więcej obrażeń, jeśli będziesz biegać lub się kręcić."
}
},
@ -1856,7 +1873,7 @@
"trophiesText": "Zdobycze",
"trophiesThisSeasonText": "Zdobycze w tym Sezonie",
"tutorial": {
"cpuBenchmarkText": "Wykonywanie testu szybkości (głównie testuje szybkość procesora)",
"cpuBenchmarkText": "Odtwarzanie samouczka na niedorzecznej prędkości (głównie testuje szybkość procesora)",
"phrase01Text": "Hejka!",
"phrase02Text": "Witaj w ${APP_NAME}!",
"phrase03Text": "Oto kilka porad jak kontrolować swoją postać:",
@ -1867,9 +1884,9 @@
"phrase08Text": "Teraz skoczymy i wykonamy obrót aby zwiększyć szybkość.",
"phrase09Text": "Ooo, tak lepiej.",
"phrase10Text": "Bieganie również pomaga.",
"phrase11Text": "Przytrzymaj dowolny przycisk aby biec.",
"phrase11Text": "Przytrzymaj dowolny przycisk, aby biec.",
"phrase12Text": "Dla uzyskania mocnych uderzeń, staraj się biegać i obracać.",
"phrase13Text": "Ojjj... sorki ${NAME}.",
"phrase13Text": "Ojjj... sorki, ${NAME}.",
"phrase14Text": "Możesz podnosić i rzucać np. flagami, bombami, a nawet przeciwnikiem - ${NAME}.",
"phrase15Text": "Ale BombSquad to głównie BOMBY.",
"phrase16Text": "Skuteczne rzucanie bombami wymaga odrobinę praktyki.",
@ -1882,7 +1899,7 @@
"phrase23Text": "Spróbuj \"przysmażyć\" lont przez sekundę lub dwie.",
"phrase24Text": "I proszę! Nieźle upieczony.",
"phrase25Text": "Cóż, to by było na tyle.",
"phrase26Text": "A teraz bierz ich tygrysie!",
"phrase26Text": "A teraz bierz ich, tygrysie!",
"phrase27Text": "Zapamiętaj to szkolenie rekrucie, a RACZEJ wrócisz żywy!",
"phrase28Text": "...może...",
"phrase29Text": "Powodzenia!",
@ -1891,10 +1908,10 @@
"randomName3Text": "Benio",
"randomName4Text": "Czesio",
"randomName5Text": "Ignaś",
"skipConfirmText": "Naprawdę chcesz pominąć samouczek? Stuknij lub naciśnij aby zatwierdzić.",
"skipConfirmText": "Naprawdę chcesz pominąć samouczek? Stuknij lub naciśnij, aby zatwierdzić.",
"skipVoteCountText": "${COUNT}/${TOTAL} pominiętych głosów",
"skippingText": "pomijam samouczek...",
"toSkipPressAnythingText": "(stuknij lub naciśnij cokolwiek aby pominąć samouczek)"
"toSkipPressAnythingText": "(stuknij lub naciśnij cokolwiek, aby pominąć samouczek)"
},
"twoKillText": "PODWÓJNE ZABÓJSTWO!",
"unavailableText": "niedostępne",
@ -1902,12 +1919,13 @@
"unlockThisInTheStoreText": "To musi zostać odblokowane w sklepie.",
"unlockThisProfilesText": "By stworzyć więcej niż ${NUM} kont, potrzebujesz:",
"unlockThisText": "Żeby to odblokować, potrzebujesz:",
"unsupportedHardwareText": "Przepraszam ale ten sprzęt nie jest obsługiwany przez tą wersję gry.",
"unsupportedControllerText": "Wybacz, ale kontroler \"${NAME}\" nie jest wspierany.",
"unsupportedHardwareText": "Przepraszam, ale ten sprzęt nie jest obsługiwany przez tę wersję gry.",
"upFirstText": "Pierwsza gra:",
"upNextText": "Kolejna, ${COUNT} gra w rozgrywce:",
"updatingAccountText": "Aktualizowanie twojego konta...",
"upgradeText": "Ulepsz",
"upgradeToPlayText": "Aby zagrać odblokuj grę w wersji \"${PRO}\".",
"upgradeToPlayText": "Aby zagrać, odblokuj grę w wersji \"${PRO}\".",
"useDefaultText": "Użyj domyślnych",
"usesExternalControllerText": "Ta gra wykorzystuje zewnętrzny kontroler jako wejście.",
"usingItunesText": "Korzystanie z aplikacji muzycznej jako ścieżki dźwiękowej...",
@ -1915,6 +1933,7 @@
"v2AccountLinkingInfoText": "Aby połączyć konta V2, użyj przycisku \"Zarządzaj Kontem\".",
"validatingBetaText": "Legalizowanie wersji Beta...",
"validatingTestBuildText": "Sprawdzanie wersji testowej...",
"viaText": "poprzez",
"victoryText": "Zwycięstwo!",
"voteDelayText": "Nie możesz zagłosować przez następne ${NUMBER} sekund",
"voteInProgressText": "Głosowanie jest już w toku.",
@ -1959,7 +1978,7 @@
"wiimoteSetupWindow": {
"copyrightText": "Prawa autorskie DarwiinRemote",
"listenText": "Nasłuchiwanie",
"macInstructionsText": "Upewnij się, że twój kontroler Wii jest wyłączony a\nBluetooth uruchomiony na twoim Mac'u, następnie\nnaciśnij 'Słuchaj'. Wsparcie dla Wiimote może być\ntroszkę ciężko kojarzone, więc musisz spróbować\nkilkakrotnie aby uzyskać połączenie.\n\nBluetooth poradzi sobie z połączeniem do 7 urządzeń,\nchociaż ta liczba może się wahać.\n\nBombSquad wspiera oryginalne Wiimotes, Nunchuks,\ni klasyczne kontrolery. Nowy Wii Remote Plus również\npowinien współpracować lecz bez dodatków.",
"macInstructionsText": "Upewnij się, że twój kontroler Wii jest wyłączony a\nBluetooth włączony na twoim Mac'u, a następnie\nnaciśnij 'Słuchaj'. Wsparcie dla Wiimote może być\ntroszkę kulawe, więc być może będziesz musiał\npopróbować kilka razy, zanim uzyskasz połączenie.\n\nBluetooth poradzi sobie z połączeniem do 7 urządzeń,\nchociaż ta liczba może się wahać.\n\nBombSquad wspiera oryginalne Wiimoty, Nunchuki\ni klasyczne kontrolery. Nowy Wii Remote Plus również\npowinien współpracować, ale nie z dodatkami.",
"thanksText": "Podziękowania dla zespołu DarwiinRemote\nza wykonanie tej możliwości.",
"titleText": "Ustawienia Wiimote"
},
@ -1974,9 +1993,9 @@
"xbox360ControllersWindow": {
"getDriverText": "Pobierz sterownik",
"macInstructions2Text": "Aby używać kontrolery bezprzewodowo, musisz posiadać odbiornik\ndostępny w zestawie 'Bezprzewodowy kontroler Xbox360 dla Windows'.\nJeden odbiornik pozwala na podłączenie do 4 kontrolerów.\n\nWażne: inne odbiorniki mogą nie współpracować ze sterownikiem;\nupewnij się, czy odbiornik posiada napis 'Microsoft', nie 'XBOX360'.\nMicrosoft nie sprzedaje odbiorników osobno, więc musisz nabyć go\nw zestawie z kontrolerem lub zakupić na aukcjach.\n\nJeśli powyższe informacje okazały się przydatne, rozważ przekazanie\ndotacji dla producenta sterownika na jego stronie.",
"macInstructionsText": "Aby użyć kontrolerów z konsoli Xbox360, musisz\nzainstalować sterownik Mac'a dostępny w poniższym linku.\nSterownik współpracuje zarówno z przewodowymi jak i\nbezprzewodowymi kontrolerami.",
"ouyaInstructionsText": "Aby skorzystać z bezprzewodowych kontrolerów konsoli Xbox360,\npodłącz je do portów USB urządzeń. Możesz skorzystać z hubu USB\naby podłączyć klika kontrolerów.\n\nAby użyć bezprzewodowe kontrolery musisz posiadać bezprzewodowy\nodbiornik, dostępny w zestawie \"Bezprzewodowy kontroler Xbox360\ndla Windows\" lub sprzedawany oddzielnie. Każdy odbiornik podłączony\ndo portu USB urządzenia pozwoli na podłączenie do 4 bezprzewodowych\nkontrolerów.",
"titleText": "Wykorzystywanie kontrolerów Xbox360 w ${APP_NAME}"
"macInstructionsText": "Aby użyć kontrolerów z Xboxa 360, musisz zainstalować\nsterownik do Maca dostępny w poniższym linku. Działa on zarówno\nz przewodowymi jak i bezprzewodowymi kontrolerami.",
"ouyaInstructionsText": "Aby skorzystać z bezprzewodowych kontrolerów konsoli Xbox 360,\npodłącz je do portów USB w twoim urządzeniu. Możesz skorzystać\nz huba USB, aby podłączyć wiele kontrolerów.\n\nAby używać bezprzewodowych kontrolerów, musisz posiadać bezprzewodowy\nodbiornik, dostępny w zestawie \"Bezprzewodowy kontroler Xbox 360 dla \nWindows\" lub sprzedawany oddzielnie. Każdy odbiornik podłączony do portu\nUSB urządzenia pozwoli na podłączenie do 4 bezprzewodowych kontrolerów.",
"titleText": "Wykorzystywanie kontrolerów Xbox 360 w ${APP_NAME}:"
},
"yesAllowText": "Dajesz!",
"yourBestScoresText": "Twoje najlepsze wyniki",

View file

@ -32,6 +32,7 @@
"signInWithGooglePlayText": "Iniciar sessão com Google Play",
"signInWithTestAccountInfoText": "(tipo de conta legado; use as contas do dispositivo daqui em diante)",
"signInWithTestAccountText": "Iniciar sessão com conta teste",
"signInWithText": "Entrar com ${SERVICE}",
"signInWithV2InfoText": "(uma conta que funciona em todas as plataformas)",
"signInWithV2Text": "Iniciar sessão com conta do BombSquad",
"signOutText": "Finalizar sessão",
@ -375,6 +376,7 @@
"chatMutedText": "Chat silenciado",
"chatUnMuteText": "Reativar som do chat",
"choosingPlayerText": "<escolhendo jogador>",
"codesExplainText": "Os códigos são fornecidos pelo desenvolvedor para \ndiagnosticar e corrigir problemas de conta.",
"completeThisLevelToProceedText": "Você deve completar \neste nível para continuar!",
"completionBonusText": "Bônus de conclusão",
"configControllersWindow": {
@ -464,6 +466,7 @@
"titleText": "Configurar touchscreen",
"touchControlsScaleText": "Escala de Toque do Controle"
},
"configureDeviceInSystemSettingsText": "${DEVICE} pode ser configurado no aplicativo \"Configurações do sistema\".",
"configureItNowText": "Configurar agora?",
"configureText": "Configurar",
"connectMobileDevicesWindow": {
@ -588,6 +591,8 @@
"disableXInputDescriptionText": "Permite mais de 4 controles mas pode não funcionar bem.",
"disableXInputText": "Desativar XInput",
"disabledText": "Desabilitado",
"discordFriendsText": "Quer procurar por pessoas para jogar com elas?\nEntre no nosso Discord e encontre novos amigos!",
"discordJoinText": "Junte-se ao Discord",
"doneText": "Concluído",
"drawText": "Empate",
"duplicateText": "Duplicar",
@ -863,10 +868,12 @@
"autoText": "Auto",
"fullScreenCmdText": "Tela cheia (Cmd-F)",
"fullScreenCtrlText": "Tela cheia (Ctrl-F)",
"fullScreenText": "Tela cheia",
"gammaText": "Gama",
"highText": "Alto",
"higherText": "Mais alto",
"lowText": "Baixo",
"maxFPSText": "FPS máximo",
"mediumText": "Médio",
"neverText": "Nunca",
"resolutionText": "Resolução",
@ -1129,6 +1136,7 @@
"noJoinCoopMidwayText": "Jogos cooperativos não podem ser afiliados no meio do caminho.",
"noProfilesErrorText": "Você não tem perfis de jogadores, então você está preso com '${NAME}'.\nVá para Configurações->Perfis de Jogador para criar um perfil.",
"noScoresYetText": "Ainda sem pontuação.",
"noServersFoundText": "Servidores não encontrados.",
"noThanksText": "Não, obrigado",
"noTournamentsInTestBuildText": "Atenção: As pontuações dos torneios desta compilação de teste serão ignoradas.",
"noValidMapsErrorText": "Nenhum mapa válido encontrado para este tipo de jogo.",
@ -1355,6 +1363,7 @@
"netTestingText": "Teste de conexão",
"resetText": "Redefinir",
"showBombTrajectoriesText": "Mostrar trajetórias da bomba",
"showDevConsoleButtonText": "Mostrar console de desenvolvedor",
"showInGamePingText": "Mostrar latência no jogo",
"showPlayerNamesText": "Mostrar nomes dos jogadores",
"showUserModsText": "Mostrar Pasta de Modificações",
@ -1450,6 +1459,8 @@
"storeText": "Loja",
"submitText": "Valor",
"submittingPromoCodeText": "Enviando código promocional...",
"successText": "Sucesso!",
"supportEmailText": "Se estiver passando por problemas com o aplicativo, \nenvie um e-mail para ${EMAIL}.",
"teamNamesColorText": "Nome/cores das equipes...",
"teamsText": "Times",
"telnetAccessGrantedText": "Acesso ao Telnet ativado.",
@ -1505,7 +1516,7 @@
"Santa Claus": "Papai Noel",
"Snake Shadow": "Serpente Sombria",
"Spaz": "Spaz",
"Taobao Mascot": "Mascote da Taobao",
"Taobao Mascot": "Mascote Taobao",
"Todd": "Teddy",
"Todd McBurton": "Todd McBurton",
"Xara": "Zara",
@ -1931,6 +1942,7 @@
"unlockThisInTheStoreText": "Isto deve ser desbloqueado na loja.",
"unlockThisProfilesText": "Para criar mais que ${NUM} perfis, você precisa:",
"unlockThisText": "Para desbloquear isso:",
"unsupportedControllerText": "Desculpe, o controlador \"${NAME}\" não é compatível.",
"unsupportedHardwareText": "Desculpe, este hardware não é suportado por esta versão do jogo.",
"upFirstText": "Em primeiro lugar:",
"upNextText": "O próximo jogo em ${COUNT}:",
@ -1944,6 +1956,7 @@
"v2AccountLinkingInfoText": "Para vincular contas V2, use o botão 'Gerenciar conta'.",
"validatingBetaText": "Validando Beta...",
"validatingTestBuildText": "Validando versão de teste...",
"viaText": "via",
"victoryText": "Vitória!",
"voteDelayText": "Você não pode começar outra votação por ${NUMBER} segundo(s)",
"voteInProgressText": "Uma votação já está em progresso.",

View file

@ -33,6 +33,7 @@
"signInWithGooglePlayText": "Войти через Google Play",
"signInWithTestAccountInfoText": "(устаревший тип аккаунта; в дальнейшем используйте аккаунт устройства)",
"signInWithTestAccountText": "Войти через тестовый аккаунт",
"signInWithText": "Войти при помощи ${SERVICE}",
"signInWithV2InfoText": "(аккаунт, который работает на всех платформах)",
"signInWithV2Text": "Войти через аккаунт BombSquad",
"signOutText": "Выйти",
@ -75,7 +76,7 @@
},
"Flawless Victory": {
"description": "Победите не получив урона",
"descriptionComplete": "Победа без получения урона",
"descriptionComplete": "Победил без получения урона",
"descriptionFull": "Пройдите уровень ${LEVEL} не получив урона",
"descriptionFullComplete": "Уровень ${LEVEL} пройден без урона",
"name": "Чистая победа"
@ -376,6 +377,7 @@
"chatMutedText": "Чат заглушен",
"chatUnMuteText": "Включить чат",
"choosingPlayerText": "<выбор игрока>",
"codesExplainText": "Коды предоставлены разработчиком, чтобы\nвыявлять и исправлять ошибки с аккаунтом.",
"completeThisLevelToProceedText": "Чтобы продолжить, нужно\nпройти этот уровень!",
"completionBonusText": "Бонус за прохождение",
"configControllersWindow": {
@ -460,6 +462,7 @@
"titleText": "Настройка сенсорного экрана",
"touchControlsScaleText": "Шкала сенсоров"
},
"configureDeviceInSystemSettingsText": "${DEVICE} может быть настроен в приложении системных настроек.",
"configureItNowText": "Настроить сейчас?",
"configureText": "Настроить",
"connectMobileDevicesWindow": {
@ -576,12 +579,14 @@
"difficultyEasyText": "Легкий",
"difficultyHardOnlyText": "Только в трудном режиме",
"difficultyHardText": "Трудный",
"difficultyHardUnlockOnlyText": "Этот уровень может быть открыт только в сложном режиме.\nДумаете, сможете!?!?!",
"difficultyHardUnlockOnlyText": "Этот уровень может быть открыт только в сложном режиме.\nДумаете, сможете это сделать!?!?!",
"directBrowserToURLText": "Пожалуйста, направьте веб-браузер по следующему адресу:",
"disableRemoteAppConnectionsText": "Отключить соединения RemoteApp",
"disableXInputDescriptionText": "Позволяет подключение более 4 контроллеров, но может не очень хорошо работать.",
"disableXInputText": "Отключить XInput",
"disabledText": "Отключено",
"discordFriendsText": "Желаете поискать новых людей с которыми можно поиграть?\nПрисоединяйтесь к нашему Discord и находите новых друзей!",
"discordJoinText": "Присоединиться к Discord",
"doneText": "Готово",
"drawText": "Ничья",
"duplicateText": "Дублировать",
@ -859,10 +864,12 @@
"alwaysText": "Всегда",
"fullScreenCmdText": "Полноэкранный (Cmd-F)",
"fullScreenCtrlText": "Полноэкранный (Ctrl-F)",
"fullScreenText": "Полный экран",
"gammaText": "Гамма",
"highText": "Высокий",
"higherText": "Ультра",
"lowText": "Низкий",
"maxFPSText": "Максимальный FPS",
"mediumText": "Средний",
"neverText": "Никогда",
"resolutionText": "Разрешение",
@ -1112,6 +1119,7 @@
"noJoinCoopMidwayText": "К кооперативным играм нельзя присоединиться посреди игры.",
"noProfilesErrorText": "У вас нет профиля игрока, так что вас будут звать '${NAME}'.\nСоздать профиль можно перейдя в 'Настройки' > 'Профили игроков'.",
"noScoresYetText": "Счета пока нет.",
"noServersFoundText": "Серверы не найдены.",
"noThanksText": "Нет, спасибо",
"noTournamentsInTestBuildText": "ВНИМАНИЕ: Турнирные очки из этой тестовой сборки будут не засчитаны.",
"noValidMapsErrorText": "Для данного типа игры не найдено корректных карт.",
@ -1331,6 +1339,7 @@
"netTestingText": "Тестирование сети",
"resetText": "Сбросить",
"showBombTrajectoriesText": "Показывать траекторию бомбы",
"showDevConsoleButtonText": "Показать кнопку консоли",
"showInGamePingText": "Показать Ping",
"showPlayerNamesText": "Показывать имена игроков",
"showUserModsText": "Показать папку модов",
@ -1426,6 +1435,8 @@
"storeText": "Магазин",
"submitText": "Отправить",
"submittingPromoCodeText": "Активация кода....",
"successText": "Успех!",
"supportEmailText": "Если вы испытываете какие-то проблемы с приложением,\nпожалуйста, напишите на почту ${EMAIL}.",
"teamNamesColorText": "имена/цвета команд",
"teamsText": "Команды",
"telnetAccessGrantedText": "Доступ Telnet включен.",
@ -1907,6 +1918,7 @@
"unlockThisInTheStoreText": "Это должно быть разблокировано в магазине.",
"unlockThisProfilesText": "Чтобы создать более ${NUM} профиль, Вам необходимо:",
"unlockThisText": "Чтобы разблокировать это, вам нужно:",
"unsupportedControllerText": "К сожалению, контроллер \"${NAME}\" не поддерживается.",
"unsupportedHardwareText": "К сожалению, это оборудование не поддерживается в этой сборке игры.",
"upFirstText": "Для начала:",
"upNextText": "Далее в игре ${COUNT}:",
@ -1920,6 +1932,7 @@
"v2AccountLinkingInfoText": "Чтобы обьединить старый и новый аккаунты, используйте кнопку 'Обьединить аккаунты'",
"validatingBetaText": "Валидация бета-версии...",
"validatingTestBuildText": "Проверка тестовой сборки...",
"viaText": "используя",
"victoryText": "Победа!",
"voteDelayText": "Невозможно начать новое голосование еще ${NUMBER} секунд",
"voteInProgressText": "Голосование уже в процессе.",

View file

@ -18,7 +18,7 @@
"linkAccountsText": "Vincular Cuentas",
"linkedAccountsText": "Cuentas Vinculadas:",
"manageAccountText": "Administrar Cuenta",
"nameChangeConfirm": "¿Seguro cambiar tu nombre a ${NAME}?",
"nameChangeConfirm": "¿Cambiar tu nombre de cuenta a ${NAME}?",
"notLoggedInText": "<no estás conectado>",
"resetProgressConfirmNoAchievementsText": "Esto reiniciará tu progreso cooperativo y \ntus puntajes locales (a excepción de tus boletos).\nEsto no puede deshacerse. ¿Estás seguro?",
"resetProgressConfirmText": "Esto reiniciará tus logros, récords\ny progreso en el modo cooperativo.\nLos cambios no se pueden deshacer.\n¿Estás seguro?",
@ -33,6 +33,7 @@
"signInWithGooglePlayText": "Iniciar sesión con Google Play",
"signInWithTestAccountInfoText": "(tipo de cuenta heredada; usa las cuentas de dispositivos más adelante)",
"signInWithTestAccountText": "Iniciar sesión con cuenta de prueba",
"signInWithText": "Iniciar sesion con ${SERVICE}",
"signInWithV2InfoText": "(una cuenta que funciona en todas las plataformas)",
"signInWithV2Text": "Iniciar sesión con una cuenta de BombSquad",
"signOutText": "Cerrar Sesión",
@ -43,10 +44,10 @@
"testAccountWarningText": "Advertencia: te estás registrando con una cuenta de\nprueba. Esta cuenta está vinculada a este dispositivo y\npuede que se reinicie periódicamente. (Así que no\ngastes mucho tiempo coleccionando/desbloqueando objetos)\n\nJuega una versión pública del juego y usa una \"cuenta real\"\n(Game-Center, Google Plus, etc.) Esto también te dejará\nguardar tu progreso en la nube y poder compartirlo con\ndiferentes dispositivos.",
"ticketsText": "Boletos: ${COUNT}",
"titleText": "Cuenta",
"unlinkAccountsInstructionsText": "Selecciona una cuenta para desenlazar",
"unlinkAccountsText": "Desenlazar Cuentas",
"unlinkLegacyV1AccountsText": "Desenlazar Cuentas Heredadas (V1)",
"v2LinkInstructionsText": "Usa este enlace para crearte una cuenta o para iniciar sesión",
"unlinkAccountsInstructionsText": "Selecciona una cuenta para desvincular",
"unlinkAccountsText": "Desvincular Cuentas",
"unlinkLegacyV1AccountsText": "Desvincular Cuentas (V1) Heredadas",
"v2LinkInstructionsText": "Usa este enlace para crearte una cuenta o para iniciar sesión.",
"viaAccount": "(cuenta vía ${NAME})",
"youAreLoggedInAsText": "Estás conectado como:",
"youAreSignedInAsText": "Has iniciado sesión como:"
@ -81,8 +82,8 @@
"name": "Victoria Impecable"
},
"Free Loader": {
"descriptionFull": "Empieza un juego de Libre-para-Todos con 2 o más jugadores",
"descriptionFullComplete": "Empezó un juego de Libre-Para-Todos con 2 o más jugadores",
"descriptionFull": "Empieza un juego de Todos-Contra-Todos con 2 o más jugadores",
"descriptionFullComplete": "Empezó un juego de Todos-Contra-Todos con 2 o más jugadores",
"name": "Cargador Libre"
},
"Gold Miner": {
@ -168,10 +169,10 @@
"name": "Mago De La ${LEVEL}"
},
"Precision Bombing": {
"description": "Gana sin ningún potenciador",
"descriptionComplete": "Has ganado sin usar ningún potenciador",
"descriptionFull": "Gana ${LEVEL} sin usar potenciadores",
"descriptionFullComplete": "Ganó ${LEVEL} sin ningún potenciador",
"description": "Gana sin potenciadores",
"descriptionComplete": "Ganó sin potenciadores",
"descriptionFull": "Gana ${LEVEL} sin potenciadores",
"descriptionFullComplete": "Ganó ${LEVEL} sin potenciadores",
"name": "Bombardeo De Precisión"
},
"Pro Boxer": {
@ -203,7 +204,7 @@
"name": "Victoria en ${LEVEL}"
},
"Pro Runaround Victory": {
"description": "Completa todas las hordas",
"description": "Completa todas las oleadas",
"descriptionComplete": "Completó todas las oleadas",
"descriptionFull": "Completa todas las oleadas en ${LEVEL}",
"descriptionFullComplete": "Completó todas las oleadas en ${LEVEL}",
@ -224,10 +225,10 @@
"name": "Victoria en ${LEVEL}"
},
"Rookie Onslaught Victory": {
"description": "Vence todas las hordas",
"descriptionComplete": "Venció todas las hordas",
"descriptionFull": "Vence todas las hordas en ${LEVEL}",
"descriptionFullComplete": "Venció todas las hordas en ${LEVEL}",
"description": "Vence todas las oleadas",
"descriptionComplete": "Venció todas las oleadas",
"descriptionFull": "Vence todas las oleadas en ${LEVEL}",
"descriptionFullComplete": "Venció todas las oleadas en ${LEVEL}",
"name": "Victoria en ${LEVEL}"
},
"Runaround God": {
@ -265,7 +266,7 @@
},
"Super Mega Punch": {
"description": "Inflige 100% de daño con un solo golpe",
"descriptionComplete": "Infligiste 100% de daño con un solo golpe",
"descriptionComplete": "Infligió 100% de daño con un solo golpe",
"descriptionFull": "Inflige 100% de daño con un golpe en ${LEVEL}",
"descriptionFullComplete": "Infligió 100% de daño con un golpe en ${LEVEL}",
"name": "Súper Mega Golpe"
@ -280,7 +281,7 @@
"TNT Terror": {
"description": "Mata a 6 chicos malos con TNT",
"descriptionComplete": "Mató a 6 chicos malos con TNT",
"descriptionFull": "Mató a 6 chicos malos con TNT en ${LEVEL}",
"descriptionFull": "Mata a 6 chicos malos con TNT en ${LEVEL}",
"descriptionFullComplete": "Mató a 6 chicos malos con TNT en ${LEVEL}",
"name": "Pirómano"
},
@ -318,28 +319,30 @@
"name": "Victoria En ${LEVEL}"
},
"Uber Onslaught Victory": {
"description": "Vence todas las hordas",
"descriptionComplete": "Venció todas las hordas",
"descriptionFull": "Vence todas las hordas en ${LEVEL}",
"descriptionFullComplete": "Venció todas las hordas en ${LEVEL}",
"description": "Vence todas las oleadas",
"descriptionComplete": "Venció todas las oleadas",
"descriptionFull": "Vence todas las oleadas en ${LEVEL}",
"descriptionFullComplete": "Venció todas las oleadas en ${LEVEL}",
"name": "Victoria En ${LEVEL}"
},
"Uber Runaround Victory": {
"description": "Completa todas las hordas",
"descriptionComplete": "Completó todas las hordas",
"descriptionFull": "Completa todas las hordas en ${LEVEL}",
"descriptionFullComplete": "Completó todas las hordas en ${LEVEL}",
"description": "Completa todas las oleadas",
"descriptionComplete": "Completó todas las oleadas",
"descriptionFull": "Completa todas las oleadas en ${LEVEL}",
"descriptionFullComplete": "Completó todas las oleadas en ${LEVEL}",
"name": "Victoria En ${LEVEL}"
}
},
"achievementsRemainingText": "Logros Pendientes:",
"achievementsText": "Logros",
"achievementsUnavailableForOldSeasonsText": "Lo sentimos, los logros específicos no están disponibles para temporadas anteriores.",
"achievementsUnavailableForOldSeasonsText": "Disculpe, los logros específicos no están disponibles para temporadas anteriores.",
"activatedText": "${THING} activado.",
"addGameWindow": {
"getMoreGamesText": "Obtén Más Juegos...",
"getMoreGamesText": "Conseguir Más Juegos...",
"titleText": "Agregar Juego"
},
"addToFavoritesText": "Añadir a Favoritos",
"addedToFavoritesText": "'${NAME}' añadido a Favoritos.",
"allText": "Todo",
"allowText": "Permitir",
"alreadySignedInText": "Tu cuenta está registrada en otro dispositivo;\npor favor cambia de cuentas o cierra el juego en tu \notro dispositivo e inténtalo de nuevo.",
@ -373,10 +376,11 @@
"cancelText": "Cancelar",
"cantConfigureDeviceText": "Lo sentimos, ${DEVICE} no es configurable.",
"challengeEndedText": "Este desafío ha terminado.",
"chatMuteText": "Silenciar chat",
"chatMutedText": "Chat silenciado",
"chatUnMuteText": "Desilenciar chat",
"chatMuteText": "Silenciar Chat",
"chatMutedText": "Chat Silenciado",
"chatUnMuteText": "Desilenciar Chat",
"choosingPlayerText": "<eligiendo jugador>",
"codesExplainText": "Los códigos son proporcionados por el desarrollador para\ndiagnosticar y corregir problemas de la cuenta.",
"completeThisLevelToProceedText": "¡Debes completar\neste nivel para avanzar!",
"completionBonusText": "Bono Por Completar",
"configControllersWindow": {
@ -462,6 +466,7 @@
"titleText": "Configura la Pantalla Táctil",
"touchControlsScaleText": "Ampliador de controles táctiles"
},
"configureDeviceInSystemSettingsText": "${DEVICE} se puede configurar en la aplicación Configuración del Sistema.",
"configureItNowText": "Configurar ahora?",
"configureText": "Configurar",
"connectMobileDevicesWindow": {
@ -481,15 +486,15 @@
"continueText": "Continuar",
"controlsText": "Controles",
"coopSelectWindow": {
"activenessAllTimeInfoText": "Esto no aplica en los rankings de 'Todo el tiempo'.",
"activenessAllTimeInfoText": "Esto no aplica a las clasificaciones de todo-el-tiempo.",
"activenessInfoText": "Este multiplicador aumenta en los días que juegas\ny disminuye cuando no juegas.",
"activityText": "Actividad",
"campaignText": "Campaña",
"challengesInfoText": "Gana premios por completar los mini-juegos.\n\nLos premios y la dificultad de los niveles incrementa\ncada vez que se completa y\ndecrece cuando uno expira o no se cumple.",
"challengesText": "Desafíos",
"currentBestText": "Mejor del Momento",
"currentBestText": "Mejor Actual",
"customText": "Personalizado",
"entryFeeText": "Precio",
"entryFeeText": "Entrada",
"forfeitConfirmText": "¿Renunciar a este desafío?",
"forfeitNotAllowedYetText": "Todavía no puedes abandonar este desafío.",
"forfeitText": "Abandonar",
@ -505,11 +510,11 @@
"powerRankingPointsMultText": "(x ${NUMBER} pts)",
"powerRankingPointsText": "${NUMBER} pts",
"powerRankingPointsToRankedText": "(${CURRENT} de ${REMAINING} pts)",
"powerRankingText": "Clasificación de Poder",
"powerRankingText": "Clasificación De Poder",
"prizesText": "Premios",
"proMultInfoText": "Los jugadores con la mejora ${PRO}\nreciben una bonificación del ${PERCENT}% de puntos.",
"seeMoreText": "Más...",
"skipWaitText": "Saltar la Espera",
"skipWaitText": "Omitir La Espera",
"timeRemainingText": "Tiempo Restante",
"titleText": "Modo cooperativo",
"toRankedText": "Para Clasificar",
@ -573,17 +578,19 @@
"demoText": "Demo",
"denyText": "Denegar",
"deprecatedText": "Obsoleto",
"desktopResText": "Resolución de Escritorio",
"desktopResText": "Resolución De Escritorio",
"deviceAccountUpgradeText": "Advertencia:\nIniciaste sesión con una cuenta de dispositivo (${NAME}).\nLas cuentas de dispositivo serán removidas en una futura actualización.\nActualiza a una cuenta V2 si quieres conservar tu progreso.",
"difficultyEasyText": "Fácil",
"difficultyHardOnlyText": "Solo Modo Difícil",
"difficultyHardText": "Difícil",
"difficultyHardUnlockOnlyText": "Este nivel solo puede ser desbloqueado en modo difícil.\n¡¿¡¿¡Piensas tener lo que se necesita!?!?!",
"directBrowserToURLText": "Por favor abre la siguiente URL en tu navegador:",
"disableRemoteAppConnectionsText": "Deshabilitar Conexiones Remotas de la Aplicación",
"disableRemoteAppConnectionsText": "Deshabilitar Conexiones Remotas De La Aplicación",
"disableXInputDescriptionText": "Permite más de 4 controladores pero puede que no funcione bien.",
"disableXInputText": "Deshabilitar XInput",
"disabledText": "Deshabilitado",
"discordFriendsText": "¿Quieres buscar gente nueva con quien jugar?\n¡Únete a nuestro Discord y encuentra nuevos amigos!",
"discordJoinText": "Únete a el Discord",
"doneText": "Hecho",
"drawText": "Empate",
"duplicateText": "Duplicar",
@ -594,11 +601,11 @@
"cantSaveEmptyListText": "¡No puedes guardar una lista de juegos vacía!",
"editGameText": "Editar\nJuego",
"gameListText": "Lista de juegos",
"listNameText": "Nombre de la Lista de juegos",
"listNameText": "Nombre De La Lista De Juegos",
"nameText": "Nombre",
"removeGameText": "Remover\nJuego",
"saveText": "Guardar Lista",
"titleText": "Editor de Lista de juegos"
"titleText": "Editor De Lista De Juegos"
},
"editProfileWindow": {
"accountProfileInfoText": "Este perfil de jugador especial tiene un nombre\ny un icono basado en tu cuenta.\n\n${ICONS}\n\nCrea perfiles personalizados si quieres usar\ndiferentes nombres o iconos personalizados.",
@ -608,15 +615,15 @@
"characterText": "personaje",
"checkingAvailabilityText": "Revisando la disponibilidad para \"${NAME}\"...",
"colorText": "color",
"getMoreCharactersText": "Obtener Más Personajes...",
"getMoreIconsText": "Obtener Más Iconos...",
"getMoreCharactersText": "Conseguir Más Personajes...",
"getMoreIconsText": "Conseguir Más Iconos...",
"globalProfileInfoText": "Los perfiles globales tienen un nombre único\na nivel mundial. También tienen iconos personalizados.",
"globalProfileText": "(perfil global)",
"highlightText": "resalte",
"iconText": "icono",
"localProfileInfoText": "Los perfiles locales no tienen iconos y no hay garantía\nque los nombres sean únicos. Obtén un perfil global\npara reservar un nombre único y tengas un icono personalizado.",
"localProfileInfoText": "Los perfiles locales no tienen iconos y no hay garantía\nque los nombres sean únicos. Crea un perfil global\npara reservar un nombre único y tengas un icono personalizado.",
"localProfileText": "(perfil local)",
"nameDescriptionText": "Nombre del Jugador",
"nameDescriptionText": "Nombre Del Jugador",
"nameText": "Nombre",
"randomText": "aleatorio",
"titleEditText": "Editar Perfil",
@ -639,24 +646,24 @@
"duplicateText": "Duplicar\nBanda Sonora",
"editSoundtrackText": "Editor de Banda Sonora",
"editText": "Editar\nBanda Sonora",
"fetchingITunesText": "buscando playlists en la App de Música...",
"fetchingITunesText": "buscando playlists en la App De Música...",
"musicVolumeZeroWarning": "Advertencia: el volumen de la música está en 0",
"nameText": "Nombre",
"newSoundtrackNameText": "Mi Banda Sonora ${COUNT}",
"newSoundtrackText": "Nueva Banda Sonora:",
"newText": "Nueva\nBanda Sonora",
"selectAPlaylistText": "Selecciona Una Playlist",
"selectASourceText": "Fuente de la Música",
"selectASourceText": "Fuente De La Música",
"soundtrackText": "pista de audio",
"testText": "prueba",
"titleText": "Bandas Sonoras",
"useDefaultGameMusicText": "Música del Juego Predeterminada",
"useITunesPlaylistText": "Playlist de la App de Música",
"useMusicFileText": "Archivo de Audio (MP3, etc)",
"useDefaultGameMusicText": "Música Del Juego Por Defecto",
"useITunesPlaylistText": "Playlist De La App De Música",
"useMusicFileText": "Archivo De Música (mp3, etc)",
"useMusicFolderText": "Carpeta de Archivos de Audio"
},
"editText": "Editar",
"enabledText": "Activado",
"enabledText": "Habilitado",
"endText": "Fin",
"enjoyText": "¡Diviértete!",
"epicDescriptionFilterText": "${DESCRIPTION} En cámara lenta épica.",
@ -684,11 +691,11 @@
"finalTimeText": "Tiempo Final",
"finishingInstallText": "Instalación casi lista; espera un momento...",
"fireTVRemoteWarningText": "* Para una mejor experiencia, \nutiliza controles o instala la\napp '${REMOTE_APP_NAME}' en tus\ndispositivos móviles.",
"firstToFinalText": "Primero de ${COUNT} Final",
"firstToSeriesText": "Primero de ${COUNT} Serie",
"fiveKillText": "¡¡¡ASESINATO QUÍNTUPLE!!!",
"flawlessWaveText": Horda perfecta!",
"fourKillText": "¡¡¡ASESINATO CUÁDRUPLE!!!",
"firstToFinalText": "Primero de ${COUNT} Finales",
"firstToSeriesText": "Primero de ${COUNT} Series",
"fiveKillText": "¡¡¡COMBO QUÍNTUPLE!!!",
"flawlessWaveText": Oleada Perfecta!",
"fourKillText": "¡¡¡COMBO CUÁDRUPLE!!!",
"freeForAllText": "Pelea libre",
"friendScoresUnavailableText": "Puntaje no disponible.",
"gameCenterText": "GameCenter",
@ -709,22 +716,22 @@
"titleText": "Personalizar Playlists de ${TYPE}"
},
"gameSettingsWindow": {
"addGameText": "Agrega juego"
"addGameText": "Agregar Juego"
},
"gamepadDetectedText": "1 control detectado.",
"gamepadsDetectedText": "${COUNT} controles detectados.",
"gamesToText": "${WINCOUNT} juegos a ${LOSECOUNT}",
"gatherWindow": {
"aboutDescriptionLocalMultiplayerExtraText": "Recuerda: cualquier dispositivo en la fiesta puede\ntener más de un jugador si tienen controles suficientes.",
"aboutDescriptionText": "Usa estas pestañas para crear una fiesta.\n\nLas fiestas te permiten jugar y competir con\ntus amigos con sus propios dispositivos.\n\nUsa el botón ${PARTY} en la parte superior\nderecha para chatear e interactuar con tu fiesta.\n(En el control, presiona ${BUTTON} mientras estés en el menú)",
"aboutText": "Acerca de",
"aboutDescriptionText": "Usa estas pestañas para armar una partida.\n\nLas partidas te permiten jugar y competir con\ntus amigos a través de diferentes dispositivos.\n\nUsa el botón ${PARTY} en la parte superior\nderecha para chatear e interactuar con tu partida.\n(En el control, presiona ${BUTTON} mientras estés en el menú)",
"aboutText": "Acerca De",
"addressFetchErrorText": "<error consiguiendo dirección>",
"appInviteInfoText": "Invita amigos a probar BombSquad y recibirán\n${COUNT} ticketes gratis. Tu obtendrás\n${YOU_COUNT} por cada amigo que acepte.",
"appInviteMessageText": "${NAME} te envió ${COUNT} boletos en ${APP_NAME}",
"appInviteSendACodeText": "Envíales Un Código",
"appInviteTitleText": "Invitación De La Aplicación ${APP_NAME}",
"bluetoothAndroidSupportText": "(funciona con cualquier dispositivo Android con Bluetooth)",
"bluetoothDescriptionText": "Alojar/unirse a una fiesta vía Bluetooth:",
"bluetoothDescriptionText": "Alojar/unirse a una partida vía Bluetooth:",
"bluetoothHostText": "Alojar vía Bluetooth",
"bluetoothJoinText": "Unirse vía Bluetooth",
"bluetoothText": "Bluetooth",
@ -738,7 +745,7 @@
"emailItText": "Envíar Correo",
"favoritesSaveText": "Guardar Como Favorito",
"favoritesText": "Favoritos",
"freeCloudServerAvailableMinutesText": "El siguiente server estara disponible en ${MINUTES} minutos",
"freeCloudServerAvailableMinutesText": "El siguiente servidor estará disponible en ${MINUTES} minutos.",
"freeCloudServerAvailableNowText": "¡Servidor en la nube gratuito disponible!",
"freeCloudServerNotAvailableText": "No hay servidores en la nube gratuitos disponibles.",
"friendHasSentPromoCodeText": "Recibiste ${COUNT} boletos de ${APP_NAME} de ${NAME}",
@ -770,7 +777,7 @@
"manualConnectText": "Conectar",
"manualDescriptionText": "Unirse a una partida por dirección:",
"manualJoinSectionText": "Unirse Por Dirección",
"manualJoinableFromInternetText": "¿Se pueden unir desde internet?",
"manualJoinableFromInternetText": "¿Se pueden unir desde internet?:",
"manualJoinableNoWithAsteriskText": "NO*",
"manualJoinableYesText": "SÍ",
"manualRouterForwardingText": "*para arreglarlo, configura tu router para que redireccione el puerto UDP ${PORT} a tu dirección local",
@ -779,6 +786,7 @@
"manualYourLocalAddressText": "Tu dirección local:",
"nearbyText": "Cerca",
"noConnectionText": "<sin conexión>",
"noPartiesAddedText": "Sin Fiestas Añadidas",
"otherVersionsText": "(otras versiones)",
"partyCodeText": "Código De La Partida",
"partyInviteAcceptText": "Aceptar",
@ -787,7 +795,7 @@
"partyInviteIgnoreText": "Ignorar",
"partyInviteText": "${NAME} te ha invitado\na unirse a su partida!",
"partyNameText": "Nombre De La Partida",
"partyServerRunningText": "Tu servidor de fiesta se esta ejecutando.",
"partyServerRunningText": "Tu servidor de partida se esta ejecutando.",
"partySizeText": "tamaño de partida",
"partyStatusCheckingText": "comprobando estado...",
"partyStatusJoinableText": "ahora se pueden unir a tu partida desde internet",
@ -843,9 +851,9 @@
"ticketsFromASponsorText": "Ver un anuncio\na cambio de ${COUNT} boletos",
"ticketsText": "${COUNT} Boletos",
"titleText": "Conseguir Boletos",
"unavailableLinkAccountText": "Lo sentimos, las compras no están disponibles en esta plataforma.\nComo una solución, puedes enlazar esta cuenta a otra\nplataforma y hacer tus compras desde ahí.",
"unavailableLinkAccountText": "Disculpe, las compras no están disponibles en esta plataforma.\nComo una solución, puedes enlazar esta cuenta a otra\nplataforma y hacer tus compras desde ahí.",
"unavailableTemporarilyText": "No disponible por el momento; por favor inténtalo más tarde.",
"unavailableText": "Lo sentimos, no se encuentra disponible.",
"unavailableText": "Disculpe, esto no esta disponible.",
"versionTooOldText": "Lo sentimos, esta versión del juego es muy antigua; por favor actualízala a una nueva versión.",
"youHaveShortText": "tienes ${COUNT}",
"youHaveText": "tienes ${COUNT} boletos"
@ -858,10 +866,12 @@
"alwaysText": "Siempre",
"fullScreenCmdText": "Pantalla completa (Cmd-F)",
"fullScreenCtrlText": "Pantalla completa (Ctrl-F)",
"fullScreenText": "Pantalla completa",
"gammaText": "Gama",
"highText": "Alta",
"higherText": "Muy Alta",
"lowText": "Baja",
"maxFPSText": "FPS Máximos",
"mediumText": "Mediana",
"neverText": "Nunca",
"resolutionText": "Resolución",
@ -940,25 +950,25 @@
"importText": "Importar",
"importingText": "Importando...",
"inGameClippedNameText": "en el juego será\n\"${NAME}\"",
"installDiskSpaceErrorText": "ERROR: Incapaz de completar la instalación\nPuede que te hayas quedado sin espacio.\nLibera un poco de tu espacio e intenta de nuevo.",
"installDiskSpaceErrorText": "ERROR: Incapaz de completar la instalación.\nPuede que te hayas quedado sin espacio.\nLibera un poco de tu espacio e intenta de nuevo.",
"internal": {
"arrowsToExitListText": "pulsa ${LEFT} o ${RIGHT} para salir de la lista",
"buttonText": "botón",
"cantKickHostError": "No puedes expulsar al host",
"chatBlockedText": "A ${NAME} le hemos bloqueado el chat por ${TIME} segundos.",
"connectedToGameText": "'${NAME}' se unió",
"connectedToPartyText": "¡Unido a la fiesta de ${NAME}!",
"cantKickHostError": "No puedes expulsar al anfitrión.",
"chatBlockedText": "${NAME} esta bloqueado del chat por ${TIME} segundos.",
"connectedToGameText": "Unido a '${NAME}'",
"connectedToPartyText": "¡Unido a la partida de ${NAME}!",
"connectingToPartyText": "Conectando...",
"connectionFailedHostAlreadyInPartyText": "Conexión fallida; Host esta en otra fiesta.",
"connectionFailedPartyFullText": "Conexión fallida; la fiesta está llena.",
"connectionFailedHostAlreadyInPartyText": "Conexión fallida; el anfitrión está en otra partida.",
"connectionFailedPartyFullText": "Conexión fallida; la partida está llena.",
"connectionFailedText": "Conexión fallida.",
"connectionFailedVersionMismatchText": "Conexión fallida; Host corre una versión diferente del juego.\nAsegúrese de que ambos están actualizados y vuelva a intentar.",
"connectionFailedVersionMismatchText": "Conexión fallida; el anfitrión corre una versión diferente del juego.\nAsegúrese de que ambos están actualizados y vuelva a intentar.",
"connectionRejectedText": "Conexión rechazada.",
"controllerConnectedText": "${CONTROLLER} conectado.",
"controllerDetectedText": "1 control detectado.",
"controllerDisconnectedText": "${CONTROLLER} desconectado.",
"controllerDisconnectedTryAgainText": "${CONTROLLER} desconectado. Intenta conectarlo de nuevo.",
"controllerForMenusOnlyText": "Este control no puede ser usado para jugar; solo para navegar por menus.",
"controllerForMenusOnlyText": "Este control no puede ser usado para jugar; solo para navegar por menús.",
"controllerReconnectedText": "${CONTROLLER} reconectado.",
"controllersConnectedText": "${COUNT} controles conectados.",
"controllersDetectedText": "${COUNT} controles detectados.",
@ -967,8 +977,8 @@
"errorPlayingMusicText": "Error reproduciendo música: ${MUSIC}",
"errorResettingAchievementsText": "Incapaz de reiniciar los logros; por favor inténtalo de nuevo más tarde.",
"hasMenuControlText": "${NAME} tiene el control del menú.",
"incompatibleNewerVersionHostText": "El host está corriendo una versión nueva del juego.\nActualiza a la última versión y vuelve a intentarlo.",
"incompatibleVersionHostText": "Host corre una versión diferente del juego; imposible conectar.\nAsegúrese de que ambos están actualizados y vuelva a intentar.",
"incompatibleNewerVersionHostText": "El anfitrión está ejecutando una versión nueva del juego.\nActualiza a la última versión y vuelve a intentarlo.",
"incompatibleVersionHostText": "El anfitrión está ejecutando una versión diferente del juego.\nAsegúrese de que ambos están actualizados y vuelva a intentar.",
"incompatibleVersionPlayerText": "${NAME} está ejecutando una versión diferente del juego.\nAsegúrate de que ambos estén actualizados y vuelve a intentarlo.",
"invalidAddressErrorText": "Error: dirección inválida.",
"invalidNameErrorText": "Error: nombre inválido.",
@ -977,7 +987,7 @@
"invitationsSentText": "${COUNT} invitaciones enviadas.",
"joinedPartyInstructionsText": "Alguien se ha unido a tu fiesta.\nVe a 'Jugar' para iniciar un juego.",
"keyboardText": "Teclado",
"kickIdlePlayersKickedText": "Expulsando a ${NAME} por ser inactivo.",
"kickIdlePlayersKickedText": "Expulsando a ${NAME} por estar inactivo.",
"kickIdlePlayersWarning1Text": "${NAME} será expulsado en ${COUNT} segundos si sigue inactivo.",
"kickIdlePlayersWarning2Text": "(puedes apagar esto en Ajustes -> Avanzado)",
"leftGameText": "Abandonó '${NAME}'.",
@ -996,7 +1006,7 @@
"touchScreenJoinWarningText": "Te uniste con la pantalla táctil.\nSi este fue un error, presiona 'Menú->Dejar juego' con ella.",
"touchScreenText": "Pantalla Táctil",
"trialText": "prueba",
"unableToResolveHostText": "Error: no se ha podido resolver el host",
"unableToResolveHostText": "Error: incapaz de encontrar el anfitrión.",
"unavailableNoConnectionText": "No disponible por el momento (¿No tienes conexión a internet?)",
"vrOrientationResetCardboardText": "Usa esto para reiniciar la orientación VR.\nPara jugar el juego necesitarás un control externo.",
"vrOrientationResetText": "Orientación VR reiniciada.",
@ -1012,10 +1022,10 @@
"kickOccurredText": "${NAME} ha sido expulsado.",
"kickQuestionText": "¿Expulsar a ${NAME}?",
"kickText": "Expulsar",
"kickVoteCantKickAdminsText": "Los admins no pueden ser expulsados.",
"kickVoteCantKickSelfText": "Claro que no, no puedes expulsarte a ti mismo.",
"kickVoteCantKickAdminsText": "Los administradores no pueden ser expulsados.",
"kickVoteCantKickSelfText": "No puedes expulsarte a ti mismo.",
"kickVoteFailedNotEnoughVotersText": "No hay suficientes jugadores para votar.",
"kickVoteFailedText": "Votación de expulsión fallida",
"kickVoteFailedText": "Votación de expulsión fallida.",
"kickVoteStartedText": "Se ha iniciado una votación de expulsión para '${NAME}'.",
"kickVoteText": "Votar para Expulsar",
"kickVotingDisabledText": "El voto para expulsar no está disponible.",
@ -1070,9 +1080,9 @@
"mainMenu": {
"creditsText": "Créditos",
"demoMenuText": "Menú Demo",
"endGameText": "Terminar juego",
"endTestText": "Terminar prueba",
"exitGameText": "Salir del juego",
"endGameText": "Terminar Juego",
"endTestText": "Terminar Prueba",
"exitGameText": "Salir Del Juego",
"exitToMenuText": "¿Salir al menú?",
"howToPlayText": "Cómo Jugar",
"justPlayerText": "(Solo ${NAME})",
@ -1100,14 +1110,14 @@
"mostViolatedPlayerText": "Jugador Más Violado",
"mostViolentPlayerText": "Jugador Más Violento",
"moveText": "Mover",
"multiKillText": "¡¡¡ASESINATO-${COUNT}!!!",
"multiKillText": "¡¡¡COMBO DE ${COUNT}!!!",
"multiPlayerCountText": "${COUNT} jugadores",
"mustInviteFriendsText": "Nota: debes invitar a tus amigos en\nel panel \"${GATHER}\" o conectar\ncontroles para jugar multijugador.",
"nameBetrayedText": "${NAME} traicionó a ${VICTIM}.",
"nameDiedText": "${NAME} ha muerto.",
"nameKilledText": "${NAME} mató a ${VICTIM}.",
"nameNotEmptyText": "¡El nombre no puede quedar vacío!",
"nameScoresText": "¡${NAME} anotó!",
"nameScoresText": "¡${NAME} Anotó!",
"nameSuicideKidFriendlyText": "${NAME} murió por accidente.",
"nameSuicideText": "${NAME} cometió suicidio.",
"nameText": "Nombre",
@ -1123,8 +1133,10 @@
"noExternalStorageErrorText": "No se encontraron almacenamientos externos en este dispositivo",
"noGameCircleText": "Error: no registrado en GameCircle",
"noJoinCoopMidwayText": "Jugadores no pueden unirse en mitad de un juego.",
"noPluginsInstalledText": "Sin Complementos Instalados",
"noProfilesErrorText": "No haz creado ningún perfil, por lo que tendrás que llamarte '${NAME}'.\nVe a Ajustes>Perfiles para que te hagas un perfil.",
"noScoresYetText": "Sin puntuaciones aún.",
"noScoresYetText": "Sin puntajes aún.",
"noServersFoundText": "No se encontraron servidores.",
"noThanksText": "No Gracias",
"noTournamentsInTestBuildText": "ADVERTENCIA: los puntajes de los torneos en esta versión de prueba serán ignorados.",
"noValidMapsErrorText": "Mapas válidos no encontrados para este tipo de juego.",
@ -1134,14 +1146,14 @@
"notSignedInErrorText": "Debes iniciar sesión para hacer esto.",
"notSignedInGooglePlayErrorText": "Debes iniciar sesión con Google Play para hacer esto.",
"notSignedInText": "No registrado",
"notUsingAccountText": "Nota: ignorando su cuenta de ${SERVICE}.\nVaya a 'Cuenta -> Ingresar con ${SERVICE}' si quieres usarla",
"notUsingAccountText": "Nota: ignorando su cuenta de ${SERVICE}.\nVaya a 'Cuenta -> Ingresar con ${SERVICE}' si quieres usarla.",
"nothingIsSelectedErrorText": "¡No hay nada seleccionado!",
"numberText": "#${NUMBER}",
"offText": "Apagar",
"okText": "Aceptar",
"onText": "Encender",
"oneMomentText": "Un Momento...",
"onslaughtRespawnText": "${PLAYER} reaparecerá en la horda ${WAVE}",
"onslaughtRespawnText": "${PLAYER} reaparecerá en la oleada ${WAVE}",
"orText": "${A} o ${B}",
"otherText": "Otros...",
"outOfText": "(#${RANK} de ${ALL})",
@ -1150,17 +1162,17 @@
"partyWindow": {
"chatMessageText": "Mensaje Del Chat",
"emptyText": "Tu partida está vacía",
"hostText": "(anfitrión)",
"hostText": "(host)",
"sendText": "Enviar",
"titleText": "Tu Partida"
},
"pausedByHostText": "(pausado por el anfitrión)",
"pausedByHostText": "(pausado por el host)",
"perfectWaveText": "¡Oleada Perfecta!",
"pickUpBoldText": "LEVANTAR",
"pickUpText": "Recoger",
"playModes": {
"coopText": "Cooperativo",
"freeForAllText": "Libre-para-Todos",
"freeForAllText": "Todos-contra-Todos",
"multiTeamText": "Múlti-Equipo",
"singlePlayerCoopText": "Solo Un Jugador / Cooperativo",
"teamsText": "Equipos"
@ -1183,7 +1195,7 @@
"playerProfilesWindow": {
"cantDeleteAccountProfileText": "No puedes borrar el perfil de tu cuenta.",
"deleteButtonText": "Borrar\nPerfil",
"deleteConfirmText": "Borrar '${PROFILE}'?",
"deleteConfirmText": "¿Borrar '${PROFILE}'?",
"editButtonText": "Editar\nPerfil",
"explanationText": "(nombres de jugadores personalizados y apariencias para esta cuenta)",
"newButtonText": "Nuevo\nPerfil",
@ -1196,8 +1208,8 @@
"playlistsText": "Listas de juegos",
"pleaseRateText": "Si te gusta ${APP_NAME}, por favor tomate un momento\npara calificar o escribir una reseña. Esto proporcionará\ninformación útil y ayuda al soporte del futuro desarrollo del juego.\n\n¡gracias!\n-eric",
"pleaseWaitText": "Por favor, espera...",
"pluginClassLoadErrorText": "Error al cargar la clase del plugin '${PLUGIN}': ${ERROR}",
"pluginInitErrorText": "Error al iniciar el plugin '${PLUGIN}': ${ERROR}",
"pluginClassLoadErrorText": "Error cargando la clase del complemento '${PLUGIN}': ${ERROR}",
"pluginInitErrorText": "Error iniciando complemento '${PLUGIN}': ${ERROR}",
"pluginSettingsText": "Ajustes De Complementos",
"pluginsAutoEnableNewText": "Auto Habilitar Nuevos Complementos",
"pluginsDetectedText": "Nuevo(s) complemento(s) detectado(s). Reinicie para activarlo(s), o configuralo(s) en ajustes.",
@ -1239,7 +1251,7 @@
"purchaseGameText": "Comprar Juego",
"purchasingText": "Comprando...",
"quitGameText": "¿Salir de ${APP_NAME}?",
"quittingIn5SecondsText": "Abandonando en 5 segundos...",
"quittingIn5SecondsText": "Saliendo en 5 segundos...",
"randomPlayerNamesText": "DEFAULT_NAMES, Pablo, Fulanito, Menganita, Martín, Franco, Pancho, Tomás, Bruno, Federico, Juan, Joaquín, Huevo Duro, Chico Rico",
"randomText": "Generar",
"rankText": "Rango",
@ -1254,7 +1266,7 @@
"app_name_short": "BSRemoto",
"button_position": "Posición De Los Botones",
"button_size": "Tamaño De Los Botones",
"cant_resolve_host": "No se encuentra el alojador.",
"cant_resolve_host": "No se encuentra el anfitrión.",
"capturing": "Captando...",
"connected": "Conectado.",
"description": "Usa tu teléfono o tableta como control para BombSquad.\nHasta 8 dispositivos pueden conectarse a la vez para un épico caos multijugador local en un solo TV o tableta",
@ -1263,11 +1275,11 @@
"dpad_floating": "flotante",
"dpad_position": "Posición Del D-Pad",
"dpad_size": "Tamaño Del D-Pad",
"dpad_type": "Tipo de D-Pad",
"dpad_type": "Tipo De D-Pad",
"enter_an_address": "Ingresa una dirección",
"game_full": "El juego está lleno o no acepta conexiones.",
"game_shut_down": "El juego se ha cerrado.",
"hardware_buttons": "Botones de Hardware",
"hardware_buttons": "Botones Del Hardware",
"join_by_address": "Unirse por dirección...",
"lag": "Lag: ${SECONDS} segundos",
"reset": "Reestablecer a predeterminado",
@ -1286,7 +1298,7 @@
"replayRenameWarningText": "Renombra \"${REPLAY}\" despues de un juego si quieres quedarte con el; o sino será reemplazado.",
"replayVersionErrorText": "Lo sentimos, esta repetición fue hecha en una\nversión diferente del juego y no se puede usar.",
"replayWatchText": "Ver Repetición",
"replayWriteErrorText": "Error creando archivo de repetición",
"replayWriteErrorText": "Error creando archivo de repetición.",
"replaysText": "Repeticiones",
"reportPlayerExplanationText": "Usa este email para reportar trampas, lenguaje inapropiado, u otro mal comportamiento.\nPor favor, describelo aquí abajo:",
"reportThisPlayerCheatingText": "Trampas",
@ -1303,8 +1315,8 @@
"scanScriptsMultipleModulesNeedUpdatesText": "Los ${PATH} y ${NUM} y otros módulo(s) se deberán actualizar para el api ${API}",
"scanScriptsSingleModuleNeedsUpdatesText": "${PATH} se deberá actualizar para el api ${API}",
"scoreChallengesText": "Desafíos De Puntuación",
"scoreListUnavailableText": "La lista de puntuaciones no está disponible.",
"scoreText": "Puntuación",
"scoreListUnavailableText": "La lista de puntajes no está disponible.",
"scoreText": "Puntaje",
"scoreUnits": {
"millisecondsText": "Milisegundos",
"pointsText": "Puntos",
@ -1332,7 +1344,7 @@
"benchmarksText": "Puntos De Referencia & Pruebas De Estrés",
"disableCameraGyroscopeMotionText": "Deshabilitar El Movimiento Del Giroscopio De La Cámara",
"disableCameraShakeText": "Deshabilitar El Temblor De La Cámara",
"disableThisNotice": "(puedes desactivar este aviso en ajustes avanzados)",
"disableThisNotice": "(puedes deshabilitar este aviso en ajustes avanzados)",
"enablePackageModsDescriptionText": "(enciende modificaciones pero apaga juegos vía red)",
"enablePackageModsText": "Encender Modificaciones Locales",
"enterPromoCodeText": "Ingresar Código",
@ -1347,7 +1359,8 @@
"mustRestartText": "Tienes que reiniciar el juego para que tome efecto.",
"netTestingText": "Prueba De Red",
"resetText": "Reiniciar",
"showBombTrajectoriesText": "Mostrar Trajectorias De Las Bombas",
"showBombTrajectoriesText": "Mostrar Trayectorias De Las Bombas",
"showDevConsoleButtonText": "Mostrar Botón de Consola de Desarrollador",
"showInGamePingText": "Mostrar Ping En El Juego",
"showPlayerNamesText": "Mostrar Nombres De Los Jugadores",
"showUserModsText": "Mostrar Carpeta De Mods",
@ -1403,7 +1416,7 @@
"charactersText": "Personajes",
"comingSoonText": "Próximamente...",
"extrasText": "Extras",
"freeBombSquadProText": "BombSquad ahora es gratis, pero ya que compraste el juego recibirás\nla mejora de BombSquad Pro y ${COUNT} boletos como agradecimiento.\n¡Disfruta de las nuevas funciones, y gracias por tu apoyo!\n-Eric",
"freeBombSquadProText": "BombSquad es gratis, pero ya que compraste el juego recibirás\nla mejora de BombSquad Pro y ${COUNT} boletos como agradecimiento.\n¡Disfruta de las nuevas funciones, y gracias por tu apoyo!\n-Eric",
"gameUpgradesText": "Mejoras",
"getCoinsText": "Obtén monedas",
"holidaySpecialText": "¡Especial De Temporada!",
@ -1425,7 +1438,7 @@
"salePercentText": "(${PERCENT}% menos)",
"saleText": "OFERTA",
"searchText": "Buscar",
"teamsFreeForAllGamesText": "Juegos de Equipos / Libre-para-Todos",
"teamsFreeForAllGamesText": "Juegos de Equipos / Todos-para-Todos",
"totalWorthText": "*** ¡${TOTAL_WORTH} de valor! ***",
"upgradeQuestionText": "¿Mejorar?",
"winterSpecialText": "Especial De Invierno",
@ -1438,21 +1451,23 @@
"customize2Text": "Personaliza personajes, mini-juegos, e incluso la banda sonora.",
"customizeText": "Modifica personajes y crea tus propias listas de mini-juegos.",
"sportsMoreFunText": "Los deportes son más divertidos con explosivos.",
"teamUpAgainstComputerText": "Forma equipo contra la computadora."
"teamUpAgainstComputerText": "Forma un equipo contra la computadora."
},
"storeText": "Tienda",
"submitText": "Enviar",
"submittingPromoCodeText": "Enviando Código...",
"successText": "¡Éxito!",
"supportEmailText": "Si estas teniendo algun problema con la\napp, porfavor manda un email a ${EMAIL}.",
"teamNamesColorText": "Nombres De Equipos/Colores...",
"teamsText": "Equipos",
"telnetAccessGrantedText": "Acceso a Telnet activado.",
"telnetAccessText": "Acceso a Telnet detectado; ¿permitir?",
"testBuildErrorText": "Esta versión de prueba ya no es activa; busca una versión más nueva.",
"testBuildText": "Versión De Prueba",
"testBuildValidateErrorText": "Imposible validar esta versión de prueba (¿no tienes conexión a internet?)",
"testBuildValidatedText": "Versión de Prueba Validada; ¡Disfruta!",
"testBuildText": "Compilación De Prueba",
"testBuildValidateErrorText": "Incapaz de validar esta compilación de prueba (¿no tienes conexión a internet?)",
"testBuildValidatedText": "Compilación De Prueba Validada; ¡Disfruta!",
"thankYouText": "¡Gracias por tu ayuda! ¡¡Disfruta el juego!!",
"threeKillText": "¡¡ASESINATO TRIPLE!!",
"threeKillText": "¡¡COMBO TRIPLE!!",
"timeBonusText": "Bono De Tiempo",
"timeElapsedText": "Tiempo Transcurrido",
"timeExpiredText": "Tiempo Expirado",
@ -1482,7 +1497,7 @@
"Butch": "Butch",
"Easter Bunny": "Conejo De Pascua",
"Flopsy": "Pelusa",
"Frosty": "Escarchy",
"Frosty": "Frosty",
"Gretel": "Gretel",
"Grumbledorf": "Grumbledorf",
"Jack Morgan": "Jack Morgan",
@ -1527,7 +1542,7 @@
"Onslaught": "Matanza Infinita",
"Onslaught Training": "Entrenamiento De Matanza",
"Pro ${GAME}": "${GAME} Pro",
"Pro Football": "Fútbol Pro",
"Pro Football": "Rugby Pro",
"Pro Onslaught": "Matanza Pro",
"Pro Runaround": "Evasiva Pro",
"Rookie ${GAME}": "Novato ${GAME}",
@ -1553,7 +1568,7 @@
"Get the flag to the enemy end zone.": "Lleva la bandera enemiga a tu zona.",
"How fast can you defeat the ninjas?": "¿Cuán rápido puedes derrotar a los ninjas?",
"Kill a set number of enemies to win.": "Mata a un número determinado de enemigos para ganar.",
"Last one standing wins.": "El último de pie gana.",
"Last one standing wins.": "El último en pie gana.",
"Last remaining alive wins.": "El último en quedar vivo gana.",
"Last team standing wins.": "El último equipo en pie gana.",
"Prevent enemies from reaching the exit.": "Evita que los enemigos lleguen a la salida.",
@ -1581,7 +1596,7 @@
"carry the flag for ${ARG1} seconds": "carga la bandera por ${ARG1} segundos.",
"kill ${ARG1} enemies": "mata a ${ARG1} enemigos",
"last one standing wins": "el último en pie gana",
"last team standing wins": "el último equipo en caer gana",
"last team standing wins": "el último equipo en pie gana",
"return ${ARG1} flags": "devuelve ${ARG1} banderas",
"return 1 flag": "devuelve 1 bandera",
"run ${ARG1} laps": "da ${ARG1} vueltas",
@ -1669,7 +1684,7 @@
"Big G": "Gran G",
"Bridgit": "Puentecito",
"Courtyard": "Patio Real",
"Crag Castle": "Castillo De Piedra",
"Crag Castle": "Castillo Del Risco",
"Doom Shroom": "Hongo De La Muerte",
"Football Stadium": "Estadio De Fútbol",
"Happy Thoughts": "Pensamientos Felices",
@ -1694,78 +1709,78 @@
"scoreNames": {
"Flags": "Banderas",
"Goals": "Goles",
"Score": "Puntuación",
"Score": "Puntaje",
"Survived": "Sobrevivió",
"Time": "Tiempo",
"Time Held": "Tiempo Mantenido"
},
"serverResponses": {
"A code has already been used on this account.": "Este código ya ha sido usado en esta cuenta",
"A code has already been used on this account.": "Este código ya ha sido usado en esta cuenta.",
"A reward has already been given for that address.": "Ya se le ha dado una recompensa a esa dirección.",
"Account linking successful!": Enlace de cuenta exitoso!",
"Account unlinking successful!": "¡Desenlace de cuenta exitoso!",
"Accounts are already linked.": "Las cuentas ya se encuentran enlazadas.",
"Account linking successful!": Vinculación de cuenta exitosa!",
"Account unlinking successful!": "¡Desvinculación de cuenta exitosa!",
"Accounts are already linked.": "Las cuentas ya están vinculadas.",
"Ad view could not be verified.\nPlease be sure you are running an official and up-to-date version of the game.": "No se pudo verificar la vista del anuncio. \nPor favor asegúrese de estar ejecutando una versión oficial y actualizada del juego.",
"An error has occurred; (${ERROR})": "Se ha producido un error; (${ERROR})",
"An error has occurred; please contact support. (${ERROR})": "Se ha producido un error; por favor contácte con soporte. (${ERROR})",
"An error has occurred; please contact support@froemling.net.": "Ha ocurrido un error; contacta a support@froemling.net.",
"An error has occurred; please try again later.": "Un error ha ocurrido; por favor intenta más tarde.",
"Are you sure you want to link these accounts?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nThis cannot be undone!": "¿Quieres enlazar estas cuentas?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\n¡Esto no se puede deshacer!",
"An error has occurred; (${ERROR})": "Un error ha ocurrido; (${ERROR})",
"An error has occurred; please contact support. (${ERROR})": "Un error ha ocurrido; por favor contacta al soporte. (${ERROR})",
"An error has occurred; please contact support@froemling.net.": "Un error ha ocurrido; por favor contacta a support@froemling.net.",
"An error has occurred; please try again later.": "Un error ha ocurrido; por favor intentalo más tarde.",
"Are you sure you want to link these accounts?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nThis cannot be undone!": "¿Quieres vincular estas cuentas?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\n¡Esto no se puede deshacer!",
"BombSquad Pro unlocked!": "¡BombSquad Pro desbloqueado!",
"Can't link 2 accounts of this type.": "No puedes enlazar dos cuentas de este tipo.",
"Can't link 2 diamond league accounts.": "No pueden enlazar dos cuentas de liga diamante.",
"Can't link; would surpass maximum of ${COUNT} linked accounts.": "No se pudo enlazar; sobrepasaría el máximo de ${COUNT} cuentas enlazadas.",
"Can't link 2 accounts of this type.": "No se pueden vincular 2 cuentas de este tipo.",
"Can't link 2 diamond league accounts.": "No se pueden vincular 2 cuentas de liga diamante.",
"Can't link; would surpass maximum of ${COUNT} linked accounts.": "No se pudo vincular; sobrepasaría el máximo de cuentas vinculadas de ${COUNT}.",
"Cheating detected; scores and prizes suspended for ${COUNT} days.": "Trampa detectada; puntajes y premios suspendidos por ${COUNT} días.",
"Could not establish a secure connection.": "No se pudo establecer una conexión segura.",
"Daily maximum reached.": "Máximo diario conseguido.",
"Entering tournament...": "Entrando a torneo...",
"Entering tournament...": "Entrando al torneo...",
"Invalid code.": "Código inválido.",
"Invalid payment; purchase canceled.": "Pago inválido; compra cancelada.",
"Invalid promo code.": "Código promocional inválido.",
"Invalid purchase.": "Compra inválida.",
"Invalid tournament entry; score will be ignored.": "Entrada de torneo inválida; el puntaje será ignorado.",
"Item unlocked!": Objeto desbloqueado!",
"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)": "VINCULACÍON DENEGADO. ${ACCOUNT} contiene\ndatos significativos que TODOS SERÍAN PERDIDOS.\nPuede vincular en el orden opuesto si lo desea\n(y pierda los datos de ESTA cuenta en su lugar)",
"Link account ${ACCOUNT} to this account?\nAll existing data on ${ACCOUNT} will be lost.\nThis can not be undone. Are you sure?": "¿Enlazar ${ACCOUNT} a esta cuenta?\nTodos los datos en ${ACCOUNT} desaparecerán.\nEsto no se puede deshacer. ¿Estás seguro?",
"Max number of playlists reached.": "Número máximo de listas de reproducción alcanzado.",
"Item unlocked!": Artículo desbloqueado!",
"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)": "VINCULACIÓN DENEGADA. ${ACCOUNT} contiene\ndatos significativos que podrían PERDERSE EN SU TOTALIDAD.\nPuedes vincular en el orden opuesto si lo desea\n(y pierda los datos de ESTA cuenta en su lugar)",
"Link account ${ACCOUNT} to this account?\nAll existing data on ${ACCOUNT} will be lost.\nThis can not be undone. Are you sure?": "¿Vincular ${ACCOUNT} a esta cuenta?\nTodos los datos en ${ACCOUNT} desaparecerán.\nEsto no se puede deshacer. ¿Estás seguro?",
"Max number of playlists reached.": "Número máximo de playlits alcanzado.",
"Max number of profiles reached.": "Número máximo de perfiles alcanzado.",
"Maximum friend code rewards reached.": "Máximo de premios por códigos de amigos alcanzado.",
"Message is too long.": "El Mensaje es muy largo.",
"No servers are available. Please try again soon.": "Sin servidores disponibles. Por favor intenta después.",
"No servers are available. Please try again soon.": "Sin servidores disponibles. Por favor inténtalo después.",
"Profile \"${NAME}\" upgraded successfully.": "El perfil \"${NAME}\" se ha mejorado satisfactoriamente.",
"Profile could not be upgraded.": "El perfil no pudo ser mejorado.",
"Purchase successful!": "¡Compra exitosa!",
"Received ${COUNT} tickets for signing in.\nCome back tomorrow to receive ${TOMORROW_COUNT}.": "Has recibido ${COUNT} boletos por iniciar sesión.\nRegresa mañana para recibir ${TOMORROW_COUNT} boletos.",
"Server functionality is no longer supported in this version of the game;\nPlease update to a newer version.": "La funcionalidad del servidor ya no es compatible en esta versión del juego;\nActualiza a una versión más reciente.",
"Sorry, there are no uses remaining on this code.": "Perdón, pero no quedan usos disponibles de este código.",
"Sorry, this code has already been used.": "Perdón, este código ya ha sido usado.",
"Sorry, this code has expired.": "Perdón, este código ha expirado.",
"Sorry, this code only works for new accounts.": "Perdón, este código solo sirve para cuentas nuevas.",
"Sorry, there are no uses remaining on this code.": "Disculpe, pero no quedan usos disponibles de este código.",
"Sorry, this code has already been used.": "Disculpe, este código ya ha sido usado.",
"Sorry, this code has expired.": "Disculpe, este código ha expirado.",
"Sorry, this code only works for new accounts.": "Disculpe, este código solo funciona para cuentas nuevas.",
"Still searching for nearby servers; please try again soon.": "Todavía buscando por servidores cercanos; intente de nuevo más tarde.",
"Temporarily unavailable; please try again later.": "Temporalmente desactivado; por favor, inténtalo luego.",
"Temporarily unavailable; please try again later.": "Temporalmente indisponible; por favor inténtalo más tarde.",
"The tournament ended before you finished.": "El torneo terminó antes de que terminaras.",
"This account cannot be unlinked for ${NUM} days.": "Esta cuenta no puede ser desenlazada por ${NUM} días.",
"This account cannot be unlinked for ${NUM} days.": "Esta cuenta no puede ser desvinculada por ${NUM} días.",
"This code cannot be used on the account that created it.": "Este código no puede ser usado en la misma cuenta que ha sido creado.",
"This is currently unavailable; please try again later.": "Esto Está No Disponible actualmente; por favor inténtelo más tarde",
"This requires version ${VERSION} or newer.": "Esto requiere la versión ${VERSION} o una más nueva.",
"Tournaments disabled due to rooted device.": "Los torneos han sido desactivados debido a que tu dispositivo es root",
"Tournaments require ${VERSION} or newer": "El torneo requiere la versión ${VERSION} o versiones recientes",
"Unlink ${ACCOUNT} from this account?\nAll data on ${ACCOUNT} will be reset.\n(except for achievements in some cases)": "¿Desenlazar ${ACCOUNT} de esta cuenta?\nTodos los datos en ${ACCOUNT} se reiniciarán\n(excepto los logros en algunos casos).",
"WARNING: complaints of hacking have been issued against your account.\nAccounts found to be hacking will be banned. Please play fair.": "ADVERTENCIA: se han emitido reclamaciones de piratería contra tu cuenta.\nLas cuentas que se encuentren pirateadas serán prohibidas. Por favor, juega limpio.",
"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": "¿Quieres enlazar tu cuenta de dispositivo a esta otra?\n\nTu cuenta de dispositivo es ${ACCOUNT1}\nEsta cuenta es ${ACCOUNT2}\n\nEsto permitirá guardar tu progreso actual.\nAdvertencia: ¡Esto no se puede deshacer!",
"This is currently unavailable; please try again later.": "Esto esta indisponible actualmente; por favor inténtelo más tarde",
"This requires version ${VERSION} or newer.": "Esto requiere la versión ${VERSION} o una más reciente.",
"Tournaments disabled due to rooted device.": "Los torneos han sido deshabilitados debido a que tú dispositivo esta rooteado.",
"Tournaments require ${VERSION} or newer": "Los torneos requieren la versión ${VERSION} o una más nueva",
"Unlink ${ACCOUNT} from this account?\nAll data on ${ACCOUNT} will be reset.\n(except for achievements in some cases)": "¿Desvincular ${ACCOUNT} de esta cuenta?\nTodos los datos en ${ACCOUNT} se reiniciarán.\n(excepto los logros en algunos casos)",
"WARNING: complaints of hacking have been issued against your account.\nAccounts found to be hacking will be banned. Please play fair.": "ADVERTENCIA: se han emitido reclamaciones de hacks contra tu cuenta.\nLas cuentas que se encuentren pirateadas serán prohibidas. Por favor juega limpio.",
"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": "¿Quieres vincular tu cuenta de dispositivo a esta otra?\n\nTu cuenta de dispositivo es ${ACCOUNT1}\nEsta cuenta es ${ACCOUNT2}\n\nEsto permitirá guardar tu progreso actual.\nAdvertencia: ¡Esto no se puede deshacer!",
"You already own this!": "¡Ya posees esto!",
"You can join in ${COUNT} seconds.": "Puedes unirte en ${COUNT} segundos.",
"You don't have enough tickets for this!": "¡No tienes suficientes boletos para esto!",
"You don't own that.": "No tienes eso.",
"You got ${COUNT} tickets!": "¡Obtuviste ${COUNT} boletos!",
"You got a ${ITEM}!": Recibiste un ${ITEM}!",
"You have been promoted to a new league; congratulations!": "¡Has sido ascendido a una nueva liga! ¡Felicidades!",
"You got a ${ITEM}!": Conseguiste un ${ITEM}!",
"You have been promoted to a new league; congratulations!": "Has sido ascendido a una nueva liga; ¡felicitaciones!",
"You must update to a newer version of the app to do this.": "Debes actualizar la aplicación a una versión más reciente para hacer esto.",
"You must update to the newest version of the game to do this.": "Necesitas actualizar a la versión más reciente del juego para hacer esto.",
"You must wait a few seconds before entering a new code.": "Debes esperar unos segundos antes de ingresar un código nuevo.",
"You ranked #${RANK} in the last tournament. Thanks for playing!": "Quedaste en la posición #${RANK} en el campeonato. ¡Gracias por jugar!",
"Your account was rejected. Are you signed in?": "Tu cuenta fue rechazada. ¿Estas registrado?",
"Your copy of the game has been modified.\nPlease revert any changes and try again.": "Tu copia del juego fue modificada.\nPor favor revierte estos cambios e intenta de nuevo",
"Your copy of the game has been modified.\nPlease revert any changes and try again.": "Tu copia del juego fue modificada.\nPor favor revierte estos cambios e intenta de nuevo.",
"Your friend code was used by ${ACCOUNT}": "Tu código de amigo fue usado por ${ACCOUNT}"
},
"settingNames": {
@ -1780,7 +1795,7 @@
"8 Seconds": "8 Segundos",
"Allow Negative Scores": "Permitir Puntajes Negativos",
"Balance Total Lives": "Repartir Vidas Totales",
"Bomb Spawning": "Aparición De Bombas",
"Bomb Spawning": "Aparecer Bombas",
"Chosen One Gets Gloves": "El Elegido Consigue Guantes De Boxeo",
"Chosen One Gets Shield": "El Elegido Consigue Electro-Escudo",
"Chosen One Time": "Tiempo Del Elegido",
@ -1789,14 +1804,14 @@
"Entire Team Must Finish": "Todo el Equipo Debe Terminar",
"Epic Mode": "Modo Épico",
"Flag Idle Return Time": "Tiempo De Retorno de Bandera Inactiva",
"Flag Touch Return Time": "Toque De Bandera Tiempo De Retorno",
"Flag Touch Return Time": "Retorno de Bandera con Toque",
"Hold Time": "Retención",
"Kills to Win Per Player": "Asesinatos para Ganar Por Jugador",
"Laps": "Vueltas",
"Lives Per Player": "Vidas Por Jugador",
"Long": "Largo",
"Longer": "Más Largo",
"Mine Spawning": "Minas Apareciendo",
"Mine Spawning": "Aparecer Minas",
"No Mines": "Sin Minas",
"None": "Ninguno",
"Normal": "Normal",
@ -1810,9 +1825,9 @@
"Time Limit": "Límite De Tiempo"
},
"statements": {
"${TEAM} is disqualified because ${PLAYER} left": "El equipo ${TEAM} ha sido descalificado porque ${PLAYER} se ha ido.",
"${TEAM} is disqualified because ${PLAYER} left": "${TEAM} ha sido descalificado porque ${PLAYER} se ha ido",
"Killing ${NAME} for skipping part of the track!": "¡Matando a ${NAME} por saltarse un pedazo de la pista!",
"Warning to ${NAME}: turbo / button-spamming knocks you out.": "Advertencia para ${NAME}: turbo / El spameo de botones te noqueará."
"Warning to ${NAME}: turbo / button-spamming knocks you out.": "Advertencia para ${NAME}: turbo / spam de botones te noqueará."
},
"teamNames": {
"Bad Guys": "Chicos Malos",
@ -1821,17 +1836,17 @@
"Red": "Rojo"
},
"tips": {
"A perfectly timed running-jumping-spin-punch can kill in a single hit\nand earn you lifelong respect from your friends.": "Un 'corre-salta-gira-golpea' perfecto puede destrozar de un solo impacto\ny ganarte el respeto de tus amigos para toda la vida.",
"A perfectly timed running-jumping-spin-punch can kill in a single hit\nand earn you lifelong respect from your friends.": "Un corre-salta-gira-golpea perfecto puede destrozar de un solo impacto\ny ganarte el respeto de tus amigos para toda la vida.",
"Always remember to floss.": "Siempre acuérdate de cepillar tus dientes.",
"Create player profiles for yourself and your friends with\nyour preferred names and appearances instead of using random ones.": "Crea perfiles para ti y tus amigos con nombres\ny colores personalizados en vez de usar aleatorios.",
"Curse boxes turn you into a ticking time bomb.\nThe only cure is to quickly grab a health-pack.": "Las cajas de maldición te convierten en una bomba de tiempo.\nLa única cura es agarrar rápidamente un botiquín.",
"Despite their looks, all characters' abilities are identical,\nso just pick whichever one you most closely resemble.": "A pesar de su apariencia, las habilidades de todos los personajes\nson idénticas, así que escoge el que más se parezca a ti.",
"Despite their looks, all characters' abilities are identical,\nso just pick whichever one you most closely resemble.": "A pesar de sus apariencias, las habilidades de todos los personajes\nson idénticas, así que escoge el que más se parezca a ti.",
"Don't get too cocky with that energy shield; you can still get yourself thrown off a cliff.": "No eres invencible con ese electro-escudo; todavía puedes caerte de un acantilado.",
"Don't run all the time. Really. You will fall off cliffs.": "No corras todo el tiempo. En serio. Te vas a caer.",
"Don't spin for too long; you'll become dizzy and fall.": "No gires por un largo tiempo; puedes marearte y caer.",
"Hold any button to run. (Trigger buttons work well if you have them)": "Mantén cualquier botón para correr. (Los botones de gatillo son para eso)",
"Hold down any button to run. You'll get places faster\nbut won't turn very well, so watch out for cliffs.": "Mantén pulsado cualquier botón para correr. Llegarás a lugares más rápido\npero no girarás muy bien, así que ten cuidado con los acantilados.",
"Ice bombs are not very powerful, but they freeze\nwhoever they hit, leaving them vulnerable to shattering.": "Las Bombas de hielo no son muy potentes, pero congelan lo\nque toquen, dejando a tus enemigos vulnerables a romperse.",
"Ice bombs are not very powerful, but they freeze\nwhoever they hit, leaving them vulnerable to shattering.": "Las Bombas de Hielo no son muy potentes, pero congelan lo\nque toquen, dejando a tus enemigos vulnerables a romperse.",
"If someone picks you up, punch them and they'll let go.\nThis works in real life too.": "Si alguien te recoge, dale un golpe y te soltará.\nTambién funciona en la vida real.",
"If you are short on controllers, install the '${REMOTE_APP_NAME}' app\non your mobile devices to use them as controllers.": "Si no tienes suficientes controles, instala la aplicación '${REMOTE_APP_NAME}'\nen tus dispositivos móviles para utilizarlos como controles.",
"If you are short on controllers, install the 'BombSquad Remote' app\non your iOS or Android devices to use them as controllers.": "Te faltan controles? Instala la aplicación 'BombSquad Remote'\nen tu dispositivo iOS o Android para usarlo como control.",
@ -1840,7 +1855,7 @@
"If you pick up a curse, your only hope for survival is to\nfind a health powerup in the next few seconds.": "Si tomaste una maldición, tu única esperanza es\nencontrar un botiquín en tus últimos segundos.",
"If you stay in one place, you're toast. Run and dodge to survive..": "Si te quedas quieto, estás frito. Corre y esquiva para sobrevivir...",
"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.": "Si tienes muchos jugadores yendo y viniendo, activa 'expulsar jugadores inactivos'\nen ajustes en caso de que alguien se olvide de abandonar el juego.",
"If your device gets too warm or you'd like to conserve battery power,\nturn down \"Visuals\" or \"Resolution\" in Settings->Graphics": "Si tu dispositivo se pone caliente o te gustaría conservar batería,\nbaja los \"Visuales\" o \"Resolución\" en configuración->Gráficos",
"If your device gets too warm or you'd like to conserve battery power,\nturn down \"Visuals\" or \"Resolution\" in Settings->Graphics": "Si tu dispositivo se pone caliente o te gustaría conservar batería,\nbaja los \"Visuales\" o \"Resolución\" en Configuración->Gráficos",
"If your framerate is choppy, try turning down resolution\nor visuals in the game's graphics settings.": "Si la imagen va lenta, intenta reducir la resolución\no los visuales en los ajustes gráficos del juego.",
"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.": "En Captura la Bandera, la tuya debe estar en tu base para que anotes.\nSi el otro equipo está a punto de anotar, el arrebatar su bandera evitará que lo hagan.",
"In hockey, you'll maintain more speed if you turn gradually.": "En hockey, mantendrás tu impulso si giras gradualmente.",
@ -1849,12 +1864,12 @@
"Land-mines are a good way to stop speedy enemies.": "Las minas-terrestres son una buena manera para detener enemigos veloces.",
"Many things can be picked up and thrown, including other players. Tossing\nyour enemies off cliffs can be an effective and emotionally fulfilling strategy.": "Muchas cosas se pueden recoger y lanzar, incluyendo a otros jugadores.\nArroja a tus enemigos por los precipicios. Te sentirás mejor.",
"No, you can't get up on the ledge. You have to throw bombs.": "No, no puedes subir a la cornisa. Tienes que lanzar bombas.",
"Players can join and leave in the middle of most games,\nand you can also plug and unplug controllers on the fly.": "Jugadores pueden unirse e irse en medio de casi todos los juegos,\ntambién puedes poner o quitar controles en cualquier momento.",
"Players can join and leave in the middle of most games,\nand you can also plug and unplug controllers on the fly.": "Los jugadores pueden unirse e irse en medio de casi todos los juegos,\ntambién puedes poner o quitar controles en cualquier momento.",
"Players can join and leave in the middle of most games,\nand you can also plug and unplug gamepads on the fly.": "Los jugadores pueden unirse y abandonar en el transcurso del juego,\ny también puedes conectar y desconectar controles cuando quieras.",
"Powerups only have time limits in co-op games.\nIn teams and free-for-all they're yours until you die.": "Los poderes sólo tienen tiempo límite en juego cooperativo.\nEn los equipos y Pelea libre son tuyos hasta que seas eliminado.",
"Practice using your momentum to throw bombs more accurately.": "Práctica usando tu impulso para tirar bombas con más precisión.",
"Practice using your momentum to throw bombs more accurately.": "Practica usando tu impulso para tirar bombas con más precisión.",
"Punches do more damage the faster your fists are moving,\nso try running, jumping, and spinning like crazy.": "Los golpes hacen más daño cuanto más rápido se mueven tus puños,\nasí que intenta correr, saltar, y girar como un loco.",
"Run back and forth before throwing a bomb\nto 'whiplash' it and throw it farther.": "Corre de un lado a otro antes de lanzar una\nbomba de 'latigazo' para lanzarla lejos.",
"Run back and forth before throwing a bomb\nto 'whiplash' it and throw it farther.": "Corre de un lado a otro antes de lanzar una\nbomba para 'latiguearla' y lanzarla lejos.",
"Take out a group of enemies by\nsetting off a bomb near a TNT box.": "Elimina un gran cantidad de enemigos\nal detonar una bomba cerca de una caja TNT.",
"The head is the most vulnerable area, so a sticky-bomb\nto the noggin usually means game-over.": "La cabeza es la zona más vulnerable, una bomba pegajosa\na la cabeza usualmente significa game-over.",
"This level never ends, but a high score here\nwill earn you eternal respect throughout the world.": "Este nivel no tiene fin, pero un alto puntaje aquí\nte hará ganar el respeto eterno por todo el mundo.",
@ -1894,7 +1909,7 @@
"phrase14Text": "Puedes recoger y lanzar cosas como banderas.. o ${NAME}.",
"phrase15Text": "Por último, hay bombas.",
"phrase16Text": "Lanzar bombas bien requiere práctica.",
"phrase17Text": "¡Auch! No fue un muy buen tiro.",
"phrase17Text": "¡Auch! No fue un buen tiro.",
"phrase18Text": "Moverte ayuda a lanzarlas más lejos.",
"phrase19Text": "Saltar ayuda a lanzarlas más alto.",
"phrase20Text": "\"Latiguea\" tus bombas para hacer lanzamientos aún más lejanos.",
@ -1906,7 +1921,7 @@
"phrase26Text": "¡Ahora ve por ellos, campeón!",
"phrase27Text": "Recuerda tu entrenamiento, ¡y VOLVERÁS con vida!",
"phrase28Text": "...o a lo mejor...",
"phrase29Text": "¡Buena suerte!",
"phrase29Text": "¡Buena Suerte!",
"randomName1Text": "Federico",
"randomName2Text": "Enrique",
"randomName3Text": "Guillermo",
@ -1917,13 +1932,14 @@
"skippingText": "omitiendo el tutorial...",
"toSkipPressAnythingText": "(pulsa cualquier botón para omitir el tutorial)"
},
"twoKillText": ASESINATO DOBLE!",
"twoKillText": COMBO DOBLE!",
"unavailableText": "no disponible",
"unconfiguredControllerDetectedText": "Control desconfigurado detectado:",
"unlockThisInTheStoreText": "Esto debe ser desbloqueado en la tienda.",
"unlockThisProfilesText": "Para crear más de ${NUM} cuentas, necesitas:",
"unlockThisText": "Para desbloquear esto, necesitas:",
"unsupportedHardwareText": "Lo sentimos, este dispositivo no soporta esta versión del juego.",
"unsupportedControllerText": "Lo sentimos, el controlador \"${NAME}\" no es compatible.",
"unsupportedHardwareText": "Disculpe, este dispositivo no soporta esta compilación del juego.",
"upFirstText": "A continuación:",
"upNextText": "A continuación en el juego ${COUNT}:",
"updatingAccountText": "Actualizando tu cuenta...",
@ -1933,9 +1949,10 @@
"usesExternalControllerText": "Este juego usa un control externo como entrada.",
"usingItunesText": "Usando Aplicación De Música para la banda sonora...",
"usingItunesTurnRepeatAndShuffleOnText": "Asegúrate de que mezclar esté ENCENDIDO y repetir TODOS esté activado en iTunes.",
"v2AccountLinkingInfoText": "Para enlazar cuentas V2, usa el botón \"Administrar Cuenta\".",
"v2AccountLinkingInfoText": "Para vincular cuentas V2, usa el botón \"Administrar Cuenta\".",
"validatingBetaText": "Validando Beta…",
"validatingTestBuildText": "Validando Versión de Prueba...",
"validatingTestBuildText": "Validando Compilación De Prueba...",
"viaText": "a través de",
"victoryText": "¡Victoria!",
"voteDelayText": "No puedes iniciar otra votación por ${NUMBER} segundos.",
"voteInProgressText": "Ya hay una votación en progreso.",
@ -1944,7 +1961,7 @@
"vsText": "vs.",
"waitingForHostText": "(esperando a que ${HOST} continúe)",
"waitingForLocalPlayersText": "Esperando jugadores locales...",
"waitingForPlayersText": "esperando por jugadores para unirse...",
"waitingForPlayersText": "esperando jugadores para unirse...",
"waitingInLineText": "Esperando en línea (la partida está llena)...",
"watchAVideoText": "Ver un Vídeo",
"watchAnAdText": "Ver un Anuncio",
@ -1953,14 +1970,14 @@
"deleteReplayButtonText": "Borrar\nRepetición",
"myReplaysText": "Mis Repeticiones",
"noReplaySelectedErrorText": "Ninguna Repetición Seleccionada",
"playbackSpeedText": "Velocidad de Reproducción: ${SPEED}",
"playbackSpeedText": "Velocidad De Reproducción: ${SPEED}",
"renameReplayButtonText": "Renombrar\nRepetición",
"renameReplayText": "Renombrar \"${REPLAY}\" a:",
"renameText": "Renombrar",
"replayDeleteErrorText": "Error borrando la repetición.",
"replayNameText": "Nombre De Repetición",
"replayRenameErrorAlreadyExistsText": "Una repetición con ese nombre ya existe.",
"replayRenameErrorInvalidName": "No se puede renombrar la repetición: Nombre inválido.",
"replayRenameErrorInvalidName": "No se puede renombrar la repetición; nombre inválido.",
"replayRenameErrorText": "Error renombrando repetición.",
"sharedReplaysText": "Repeticiones Compartidas",
"titleText": "Ver",
@ -1975,7 +1992,7 @@
"wiimoteListenWindow": {
"listeningText": "Esperando controles Wii...",
"pressText": "Presiona los botones 1 y 2 simultáneamente.",
"pressText2": "En controles Wii más nuevos con Motion Plus integrado, pulsa mejor el botón 'sinc' rojo en la parte trasera.",
"pressText2": "En controles Wii más nuevos con Motion Plus integrado, pulsa mejor el botón 'sync' rojo en la parte trasera.",
"pressText2Scale": 0.55,
"pressTextScale": 1.0
},
@ -1990,7 +2007,7 @@
"titleText": "Configuración Wii"
},
"winsPlayerText": "¡${NAME} Gana!",
"winsTeamText": "¡${NAME} Gana!!",
"winsTeamText": "¡${NAME} Gana!",
"winsText": "¡${NAME} Gana!",
"workspaceSyncErrorText": "Error al sincronizar ${WORKSPACE}. Mira el registro para más detalles.",
"workspaceSyncReuseText": "No se puede sincronizar ${WORKSPACE}. Reusando la versión sincronizada anterior.",
@ -1998,7 +2015,7 @@
"worldsBestScoresText": "Mejores Puntuaciones Mundiales",
"worldsBestTimesText": "Mejores Tiempos Mundiales",
"xbox360ControllersWindow": {
"getDriverText": "Obtener Driver",
"getDriverText": "Obtener Controlador",
"macInstructions2Text": "Para usar controles inalámbricos, necesitarás el receptor que\nviene con el 'Control de Xbox 360 para Windows'.\nUn receptor te permite conectar hasta cuatro controles.\n\nImportante: Receptores de tercera mano no funcionarán con este controlador;\nasegúrate de que tu receptor tenga el logo de 'Microsoft', no 'XBOX 360'.\nMicrosoft ya no vende receptores por separado, por lo que necesitarás\nel que venía con el control, o si no tendrás que buscar uno por internet.\n\nSi encuentras que esto fue útil, por favor considera donar\nal desarrollador del controlador en su sitio de internet.",
"macInstructions2TextScale": 0.76,
"macInstructionsText": "Para usar controles de Xbox 360, necesitarás instalar\nel controlador para Mac disponible en el siguiente enlace.\nFunciona con controles con cable e inalámbricos.",
@ -2007,7 +2024,7 @@
"ouyaInstructionsTextScale": 0.8,
"titleText": "Usando Controles de Xbox 360 con ${APP_NAME}:"
},
"yesAllowText": "¡Sí, Permítir!",
"yourBestScoresText": "Tus Mejores Puntuaciones",
"yesAllowText": "¡Sí, Permitir!",
"yourBestScoresText": "Tus Mejores Puntajes",
"yourBestTimesText": "Tus Mejores Tiempos"
}

View file

@ -446,6 +446,7 @@
"swipeText": "ஸ்வைப்",
"titleText": "தொடுதிரையை உள்ளமைக்கவும்"
},
"configureDeviceInSystemSettingsText": "${DEVICE} ஐ சிஸ்டம் அமைப்புகள் பயன்பாட்டில் உள்ளமைக்க முடியும்.",
"configureItNowText": "இப்போது அதை உள்ளமைக்கவா?",
"configureText": "உள்ளமை",
"connectMobileDevicesWindow": {
@ -816,10 +817,12 @@
"alwaysText": "எப்போதும்",
"fullScreenCmdText": "முழுத்திரை (Cmd-F)",
"fullScreenCtrlText": "முழுத்திரை (Ctrl-F)",
"fullScreenText": "முழு திரை",
"gammaText": "காமா",
"highText": "உயர்",
"higherText": "அதிக",
"lowText": "குறைந்த",
"maxFPSText": "அதிக FPS",
"mediumText": "நடுத்தர",
"neverText": "ஒருபோதும்",
"resolutionText": "பகுத்தல்",
@ -1059,6 +1062,7 @@
"noExternalStorageErrorText": "இந்தச் சாதனத்தில் வெளிப்புறச் சேமிப்பு இல்லை",
"noGameCircleText": "பிழை: GameCircle இல் உள்நுழையவில்லை",
"noScoresYetText": "இன்னும் மதிப்பெண்கள் இல்லை.",
"noServersFoundText": "சேவையகங்கள் எதுவும் இல்லை.",
"noThanksText": "இல்லை, நன்றி!",
"noTournamentsInTestBuildText": "எச்சரிக்கை: இந்த சோதனை உருவாக்கத்தில் இருந்து போட்டியின் மதிப்பெண்கள் புறக்கணிக்கப்படும்.",
"noValidMapsErrorText": "இந்த விளையாட்டு வகைக்கு சரியான வரைபடங்கள் இல்லை.",
@ -1270,6 +1274,7 @@
"netTestingText": "நெட்வொர்க் சோதனை",
"resetText": "மீட்டு",
"showBombTrajectoriesText": "வெடிகுண்டு பாதைகளைக் காட்டு",
"showDevConsoleButtonText": "உருவாக்குபவர் பணியகத்தை காட்டு",
"showInGamePingText": "இன்-கேம் பிங்கைக் காட்டு",
"showPlayerNamesText": "பிளேயர் பெயர்களைக் காட்டு",
"showUserModsText": "மோட்ஸ் கோப்புறையைக் காட்டு",
@ -1361,6 +1366,7 @@
"storeText": "ஸ்டோர்",
"submitText": "சமர்ப்பிக்கவும்",
"submittingPromoCodeText": "குறியீட்டைச் சமர்ப்பிக்கிறது...",
"successText": "வெற்றி!",
"teamNamesColorText": "அணியின் பெயர்கள்/நிறங்கள்...",
"telnetAccessGrantedText": "டெல்நெட் அணுகல் இயக்கப்பட்டது.",
"telnetAccessText": "டெல்நெட் அணுகல் கண்டறியப்பட்டது; அனுமதிக்கவா?",
@ -1814,6 +1820,7 @@
"unlockThisInTheStoreText": "இதை ஸ்டோரில் திறக்க வேண்டும்.",
"unlockThisProfilesText": "${NUM} க்கும் அதிகமான சுயவிவரங்களை உருவாக்க, உங்களுக்கு இது தேவை:",
"unlockThisText": "இதைத் திறக்க, உங்களுக்குத் தேவை:",
"unsupportedControllerText": "மன்னிக்கவும், கட்டுப்படுத்தி \"${NAME}\" ஆதரிக்கப்படவில்லை.",
"unsupportedHardwareText": "மன்னிக்கவும், இந்த வன்பொருள் விளையாட்டின் உருவாக்கத்தால் ஆதரிக்கப்படவில்லை.",
"upFirstText": "முதலில் மேலே:",
"upNextText": "${COUNT} விளையாட்டில் அடுத்தது:",

View file

@ -30,6 +30,7 @@
"signInWithGooglePlayText": "ลงชื่อเข้าใช้ด้วยบัญชี Google Play",
"signInWithTestAccountInfoText": "(บัญชีทดลอง;เลือกตัวเลือกนี้เพื่อไปต่อ)",
"signInWithTestAccountText": "ลงชื่อเข้าใช้เพื่อทดลอง",
"signInWithText": "เข้าสู่ระบบด้วย ${SERVICE}",
"signInWithV2InfoText": "(บัญชีที่ใช้งานได้กับทุกแพลตฟอร์ม)",
"signInWithV2Text": "ลงชื่อเข้าใช้ด้วยบัญชี BombSquad",
"signOutText": "ออกจากระบบ",
@ -333,6 +334,7 @@
"getMoreGamesText": "รับเกมเพิ่มเติม",
"titleText": "เพิ่มเกม"
},
"allText": "ทั้งหมด",
"allowText": "ยอมรับ",
"alreadySignedInText": "บัญชีของคุณลงชื่อเข้าใช้จากอุปกรณ์อื่น\nโปรดเปลี่ยนบัญชีหรือปิดเกมของคุณ\nอุปกรณ์อื่นและลองอีกครั้ง",
"apiVersionErrorText": "ไม่สามารถโหลดโมดูล ${NAME} ได้; มันอยู่ในเวอร์ชั่น api ${VERSION_USED}; แต่เราต้องการเวอร์ชั่น ${VERSION_REQUIRED}",
@ -445,6 +447,7 @@
"swipeText": "การปัด",
"titleText": "การตั้งค่าหน้าจอสัมผัส"
},
"configureDeviceInSystemSettingsText": "",
"configureItNowText": "จะตั้งค่ามันตอนนี้หรือไม่?",
"configureText": "ตั้งค่า",
"connectMobileDevicesWindow": {
@ -1042,7 +1045,7 @@
"nameSuicideKidFriendlyText": "${NAME} ตายจากอุบัติเหตุ",
"nameSuicideText": "${NAME} ฆ่าตัวตาย",
"nameText": "ชื่อ",
"nativeText": "พื้นเมือง",
"nativeText": "ดั้งเดิม",
"newPersonalBestText": "ใหม่ส่วนตัวดีที่สุด!",
"newTestBuildAvailableText": "มีการสร้างการทดสอบที่ใหม่กว่า! (${VERSION} บิลด์ ${BUILD})\nรับได้ที่ ${ADDRESS}",
"newText": "ใหม่",
@ -1054,6 +1057,7 @@
"noExternalStorageErrorText": "ไม่พบที่จัดเก็บข้อมูลภายนอกในอุปกรณ์นี้",
"noGameCircleText": "ข้อผิดพลาด: ไม่ได้ลงชื่อเข้าใช้ GameCircle",
"noScoresYetText": "ไม่มีคะแนน",
"noServersFoundText": "ไม่พบเซิร์ฟเวอร์",
"noThanksText": "ไม่เป็นไรขอบคุณ",
"noTournamentsInTestBuildText": "คำเตือน: คะแนนการแข่งขันจากรุ่นทดสอบนี้จะถูกละเว้น",
"noValidMapsErrorText": "ไม่พบแผนที่ที่ถูกต้องสำหรับเกมนี้",

View file

@ -31,6 +31,7 @@
"signInWithGooglePlayText": "Google Play ile Giriş yap",
"signInWithTestAccountInfoText": "(miras hesabı;bu cihaz hesaplarını ileride de kullan)",
"signInWithTestAccountText": "Test hesabı ile Giriş yap",
"signInWithText": "${SERVICE} ile giriş yap.",
"signInWithV2InfoText": "(bütün platformlarda çalışan bir hesap)",
"signInWithV2Text": "BombSquad hesabıyla giriş yap",
"signOutText": ıkış Yap",
@ -368,6 +369,7 @@
"chatMutedText": "Sohbet Susturuldu",
"chatUnMuteText": "Konuşmayı aç",
"choosingPlayerText": "<oyuncu seçme>",
"codesExplainText": "Kodlar geliştirici tarafından sağlanır\nhesap sorunlarını teşhis edin ve düzeltin.",
"completeThisLevelToProceedText": "İlerlemek için bu \nseviyeyi tamamlamalısınız!",
"completionBonusText": "Tamamlama Bonusu",
"configControllersWindow": {
@ -448,6 +450,7 @@
"swipeText": "sürme",
"titleText": "Dokunmatikleri Yapılandır"
},
"configureDeviceInSystemSettingsText": "${DEVICE} Sistem ayarları uygulamasında yapılandırılabilir.",
"configureItNowText": "Şimdi yapılandır?",
"configureText": "Yapılandır",
"connectMobileDevicesWindow": {
@ -561,6 +564,8 @@
"disableXInputDescriptionText": "4 kontrolcüden fazla kullanılabilir fakat iyi çalışmayabilir.",
"disableXInputText": "XInput etkisizleştir",
"disabledText": "Kullanılmıyor",
"discordFriendsText": "Yeni oyuncularmı arıyorsun?\nDiscord sunucumuza katılarak yeni arkadaşlar edinebilirsin!",
"discordJoinText": "Discord sunucumuza katıl",
"doneText": "Tamam",
"drawText": "Beraberlik",
"duplicateText": "Kopyala",
@ -817,10 +822,12 @@
"alwaysText": "Her Zaman",
"fullScreenCmdText": "Tam Ekran (Cmd-F)",
"fullScreenCtrlText": "Tam Ekran (Ctrl-F)",
"fullScreenText": "Tam Ekran",
"gammaText": "Gama",
"highText": "Yüksek",
"higherText": "Çok Yüksek",
"lowText": "Düşük",
"maxFPSText": "Maksimum FPS",
"mediumText": "Orta",
"neverText": "Asla",
"resolutionText": "Çözünürlük",
@ -1059,6 +1066,7 @@
"noExternalStorageErrorText": "Bu cihazda harici depolama bulunamadı",
"noGameCircleText": "Hata: GameCircle girişi yapılamadı",
"noScoresYetText": "Henüz skor yok.",
"noServersFoundText": "Sunucu Bulunamadı.",
"noThanksText": "Hayır Teşekkürler",
"noTournamentsInTestBuildText": "DİKKAT: Bu test sürümündeki turnuva skorları dikkate alınmayacaktır.",
"noValidMapsErrorText": "Bu oyun tipi için geçerli harita bulunamadı.",
@ -1268,6 +1276,7 @@
"netTestingText": "Ağ Testi",
"resetText": "Sıfırla",
"showBombTrajectoriesText": "Bomba Gidişatını Göster",
"showDevConsoleButtonText": "Geliştirici panelini aç",
"showInGamePingText": "Oyun İçinde Gecikmeyi Göster",
"showPlayerNamesText": "Oyuncu Adlarını Göster",
"showUserModsText": "Mod Klasörünü Göster",
@ -1360,6 +1369,8 @@
"storeText": "Mağaza",
"submitText": "Gönder",
"submittingPromoCodeText": "Kod Gönderiliyor...",
"successText": "Başarı!",
"supportEmailText": "Uygulama ile ilgili herhangi bir sorun yaşıyorsanız,\nlütfen ${EMAIL} adresine e-posta gönderin.",
"teamNamesColorText": "Takım isimleri/Renkler...",
"telnetAccessGrantedText": "Telnet Erişimi aktif.",
"telnetAccessText": "Telnet erişimi algılandı; izin ver?",
@ -1813,6 +1824,7 @@
"unlockThisInTheStoreText": "Bunun mağazada kilidi açık olmalı.",
"unlockThisProfilesText": "${NUM} taneden daha fazla profil yaratmak için ihtiyacın olan:",
"unlockThisText": "Bu kilidi açmak için ihtiyacın olan:",
"unsupportedControllerText": "Üzgünüm, kontrolcü \"${NAME}\" desteklenmiyor.",
"unsupportedHardwareText": "Üzgünüz, bu donanım oyunun bu sürümü tarafından desteklenmiyor.",
"upFirstText": "İlki:",
"upNextText": "Sıradaki oyun ${COUNT}:",
@ -1825,6 +1837,7 @@
"usingItunesTurnRepeatAndShuffleOnText": "Lütfen iTunes da karıştırmanın KAPALI oldugundan ve Yinelemenin TÜM oldugundan emin olun. ",
"v2AccountLinkingInfoText": "V2 hesapları bağlamak için, 'Hesabı yönet' butonuna tıklayın.",
"validatingTestBuildText": "Test Yapısı Onaylanıyor...",
"viaText": "Böylede bilinir",
"victoryText": "Galibiyet!",
"voteDelayText": "${NUMBER} saniye boyunca başka oylama başlatamazsın.",
"voteInProgressText": "Oylama zaten işlemde.",

View file

@ -31,6 +31,7 @@
"signInWithGooglePlayText": "Увійти через Google Play",
"signInWithTestAccountInfoText": "(тест-аккаунт; надалі використовуйте акаунт пристрою)",
"signInWithTestAccountText": "Увійти через тестовий акаунт",
"signInWithText": "Увійти за допомогою ${SERVICE}",
"signInWithV2InfoText": "(обліковий запис, який працює на всіх платформах)",
"signInWithV2Text": "Увійдіть за допомогою облікового запису BombSquad",
"signOutText": "Вийти",
@ -449,6 +450,7 @@
"swipeText": "змахнути",
"titleText": "Налаштування сенсорного екрану"
},
"configureDeviceInSystemSettingsText": "${DEVICE} можна налаштувати в налаштуваннях системи",
"configureItNowText": "Налаштувати зараз?",
"configureText": "Налаштувати",
"connectMobileDevicesWindow": {
@ -818,10 +820,12 @@
"alwaysText": "Завжди",
"fullScreenCmdText": "Повноекранний (Cmd-F)",
"fullScreenCtrlText": "Повноекранний (Ctrl-F)",
"fullScreenText": "Повний екран",
"gammaText": "Гамма",
"highText": "Високий",
"higherText": "Вище",
"lowText": "Низький",
"maxFPSText": "Максимальна частота кадрів",
"mediumText": "Середній",
"neverText": "Ніколи",
"resolutionText": "Розширення",
@ -1060,6 +1064,7 @@
"noExternalStorageErrorText": "На цьому пристрої не знайдено зовнішньої пам'яті",
"noGameCircleText": "Помилка: не ввійшли в GameCircle",
"noScoresYetText": "Рахунка поки немає.",
"noServersFoundText": "Серверів не знайдено",
"noThanksText": "Ні дякую",
"noTournamentsInTestBuildText": "ВАЖЛИВО: Турнірні Очки на цій тестовій версії будуть ігноровані.",
"noValidMapsErrorText": "Для даного типу гри не знайдено коректних карт.",
@ -1269,6 +1274,7 @@
"netTestingText": "Тестування мережі",
"resetText": "Скинути",
"showBombTrajectoriesText": "Показувати траєкторію бомби",
"showDevConsoleButtonText": "Показати кнопку консолі адміністратора",
"showInGamePingText": "Показувати пінг у грі",
"showPlayerNamesText": "Показувати імена гравців",
"showUserModsText": "Показати теку модів",
@ -1360,6 +1366,7 @@
"storeText": "Магазин",
"submitText": "Відправити",
"submittingPromoCodeText": "Активація коду...",
"successText": "Успішно!",
"teamNamesColorText": "імена/кольори команд",
"telnetAccessGrantedText": "Доступ Telnet включений.",
"telnetAccessText": "Виявлено доступ Telnet. Дозволити?",
@ -1813,6 +1820,7 @@
"unlockThisInTheStoreText": "Це повинно бути розблоковано в магазині.",
"unlockThisProfilesText": "Щоб створити більш ${NUM} профіль, Вам необхідно:",
"unlockThisText": "Щоб розблокувати це, вам потрібно:",
"unsupportedControllerText": "Вибачте, контролер \"${NAME}\" не підтримується.",
"unsupportedHardwareText": "На жаль, це устаткування не підтримується в цій збірці гри.",
"upFirstText": "Для початку:",
"upNextText": "Далі в грі ${COUNT}:",

View file

@ -29,6 +29,7 @@
"signInWithGooglePlayText": "Conétate co Google Play",
"signInWithTestAccountInfoText": "(account de proa vecio: in fuduro dòpara un account łogałe)",
"signInWithTestAccountText": "Conétate co un account de proa",
"signInWithText": "Acedi co ${SERVICE}",
"signInWithV2InfoText": "(un account che fusiona so tute łe piataforme)",
"signInWithV2Text": "Acedi co un account BombSquad",
"signOutText": "Sortisi da l'account",
@ -365,6 +366,7 @@
"chatMutedText": "Ciacołada siłensiada",
"chatUnMuteText": "Reativa son",
"choosingPlayerText": "<sernisi zugador>",
"codesExplainText": "I còdazi i vien fornìi da'l dezviłupador par\ndiagnostegar e corèjar problemi so l'account.",
"completeThisLevelToProceedText": "Par ndar vanti te ghè\nda conpletar 'sto łeveło!",
"completionBonusText": "Premio de concruzion",
"configControllersWindow": {
@ -445,6 +447,7 @@
"swipeText": "zlizo",
"titleText": "Configura schermo tàtiłe"
},
"configureDeviceInSystemSettingsText": "Se połe configurar ${DEVICE} so łe Inpostasion de Sistema.",
"configureItNowText": "Vutu configurarlo deso?",
"configureText": "Configura",
"connectMobileDevicesWindow": {
@ -558,6 +561,8 @@
"disableXInputDescriptionText": "Dòpara pì de 4 controładori (ma co'l riscio che no i funsione ben).",
"disableXInputText": "Dezativa XInput",
"disabledText": "Dezativà",
"discordFriendsText": "Ghetu caro catar parsone nove par zugarghe insenbre?\nZóntate so'l nostro canałe Discord e cata fora amighi novi!",
"discordJoinText": "Zóntate so Discord",
"doneText": "Fato",
"drawText": "Pata",
"duplicateText": "Zdopia",
@ -814,10 +819,12 @@
"alwaysText": "Senpre",
"fullScreenCmdText": "Schermo pien (Cmd-F)",
"fullScreenCtrlText": "Schermo pien (Ctrl-F)",
"fullScreenText": "Schermo pien",
"gammaText": "Gama",
"highText": "Alta",
"higherText": "Màsema",
"lowText": "Basa",
"maxFPSText": "FPS màsemi",
"mediumText": "Mezana",
"neverText": "Mai",
"resolutionText": "Resołusion",
@ -1056,6 +1063,7 @@
"noExternalStorageErrorText": "So sto dispozidivo no ze stà catada gnauna memoria esterna",
"noGameCircleText": "Eror: no te si miga conetesto co GameCircle",
"noScoresYetText": "Gnancora gnaun puntejo.",
"noServersFoundText": "Gnaun server catà.",
"noThanksText": "Nò, grasie",
"noTournamentsInTestBuildText": "AVERTENSA: i punteji de'l tornèo de 'sta varsion de proa i vegnarà ignorài.",
"noValidMapsErrorText": "A no ze stà catà gnaun łeveło vàłido par 'sto tipo de zugo.",
@ -1265,6 +1273,7 @@
"netTestingText": "Proa de rede",
"resetText": "Reinposta",
"showBombTrajectoriesText": "Mostra trajetore bonbe",
"showDevConsoleButtonText": "Mostra boton cuadro comandi dezviłupador",
"showInGamePingText": "Mostra łatensa de'l zugo",
"showPlayerNamesText": "Mostra nomi zugadori",
"showUserModsText": "Mostra carteła modifegasion",
@ -1356,6 +1365,8 @@
"storeText": "Botega",
"submitText": "Manda",
"submittingPromoCodeText": "Trazmision còdaze...",
"successText": "A posto!",
"supportEmailText": "Se te vedi calche problema so l'apl,\nmanda na mail a ${EMAIL}.",
"teamNamesColorText": "Nome/Cołor scuadra...",
"telnetAccessGrantedText": "Aceso a telnet ativà.",
"telnetAccessText": "Rełevà aceso a telnet: vutu autorizarlo?",
@ -1809,6 +1820,7 @@
"unlockThisInTheStoreText": "Da dezblocar inte ła botega.",
"unlockThisProfilesText": "Par crear pì de ${NUM} profiłi, A te serve:",
"unlockThisText": "Par dezblocar 'sta funsion A te serve:",
"unsupportedControllerText": "El controłador \"${NAME}\" no'l ze miga suportà.",
"unsupportedHardwareText": "Ne despiaze, 'sto hardware no'l ze mìa conpatìbiłe co 'sta varsion de'l zugo.",
"upFirstText": "Par tacar:",
"upNextText": "Inte'l łeveło n°${COUNT}:",
@ -1820,6 +1832,7 @@
"usingItunesText": "Doparar l'apl de mùzega par el son de fondo...",
"v2AccountLinkingInfoText": "Par łigar un account V2 dòpara el boton 'Jestisi account'.",
"validatingTestBuildText": "Confermasion varsion de proa...",
"viaText": "co",
"victoryText": "Vitoria!",
"voteDelayText": "A no te połi tacar n'antra votasion par ${NUMBER} segondi",
"voteInProgressText": "A ze dezà in corso na votasion.",

View file

@ -1,4 +1,4 @@
from .core import contents, where
__all__ = ["contents", "where"]
__version__ = "2023.05.07"
__version__ = "2023.11.17"

View file

@ -791,34 +791,6 @@ uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2
XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
-----END CERTIFICATE-----
# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post
# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post
# Label: "Hongkong Post Root CA 1"
# Serial: 1000
# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca
# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58
# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2
-----BEGIN CERTIFICATE-----
MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx
FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg
Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG
A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr
b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ
jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn
PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh
ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9
nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h
q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED
MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC
mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3
7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB
oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs
EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO
fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi
AmvZWg==
-----END CERTIFICATE-----
# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc.
# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc.
# Label: "SecureSign RootCA11"
@ -909,49 +881,6 @@ Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
WD9f
-----END CERTIFICATE-----
# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068"
# Serial: 6047274297262753887
# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3
# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa
# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef
-----BEGIN CERTIFICATE-----
MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE
BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h
cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy
MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg
Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9
thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM
cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG
L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i
NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h
X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b
m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy
Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja
EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T
KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF
6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh
OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD
VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD
VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv
ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl
AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF
661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9
am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1
ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481
PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS
3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k
SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF
3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM
ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g
StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz
Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB
jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
-----END CERTIFICATE-----
# Issuer: CN=Izenpe.com O=IZENPE S.A.
# Subject: CN=Izenpe.com O=IZENPE S.A.
# Label: "Izenpe.com"
@ -1676,50 +1605,6 @@ HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx
SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
-----END CERTIFICATE-----
# Issuer: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi
# Subject: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi
# Label: "E-Tugra Certification Authority"
# Serial: 7667447206703254355
# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49
# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39
# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c
-----BEGIN CERTIFICATE-----
MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV
BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC
aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV
BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1
Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz
MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+
BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp
em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY
B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH
D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF
Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo
q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D
k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH
fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut
dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM
ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8
zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX
U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6
Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5
XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF
Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR
HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY
GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c
77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3
+GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK
vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6
FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl
yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P
AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD
y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d
NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA==
-----END CERTIFICATE-----
# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center
# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center
# Label: "T-TeleSec GlobalRoot Class 2"
@ -4397,73 +4282,6 @@ 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-----
# Issuer: CN=Security Communication RootCA3 O=SECOM Trust Systems CO.,LTD.
# Subject: CN=Security Communication RootCA3 O=SECOM Trust Systems CO.,LTD.
# Label: "Security Communication RootCA3"
@ -4587,3 +4405,374 @@ AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA
94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B
43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w==
-----END CERTIFICATE-----
# Issuer: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited
# Subject: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited
# Label: "Sectigo Public Server Authentication Root E46"
# Serial: 88989738453351742415770396670917916916
# MD5 Fingerprint: 28:23:f8:b2:98:5c:37:16:3b:3e:46:13:4e:b0:b3:01
# SHA1 Fingerprint: ec:8a:39:6c:40:f0:2e:bc:42:75:d4:9f:ab:1c:1a:5b:67:be:d2:9a
# SHA256 Fingerprint: c9:0f:26:f0:fb:1b:40:18:b2:22:27:51:9b:5c:a2:b5:3e:2c:a5:b3:be:5c:f1:8e:fe:1b:ef:47:38:0c:53:83
-----BEGIN CERTIFICATE-----
MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw
CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T
ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN
MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG
A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT
ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC
WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+
6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B
Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa
qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q
4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw==
-----END CERTIFICATE-----
# Issuer: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited
# Subject: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited
# Label: "Sectigo Public Server Authentication Root R46"
# Serial: 156256931880233212765902055439220583700
# MD5 Fingerprint: 32:10:09:52:00:d5:7e:6c:43:df:15:c0:b1:16:93:e5
# SHA1 Fingerprint: ad:98:f9:f3:e4:7d:75:3b:65:d4:82:b3:a4:52:17:bb:6e:f5:e4:38
# SHA256 Fingerprint: 7b:b6:47:a6:2a:ee:ac:88:bf:25:7a:a5:22:d0:1f:fe:a3:95:e0:ab:45:c7:3f:93:f6:56:54:ec:38:f2:5a:06
-----BEGIN CERTIFICATE-----
MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD
Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw
HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY
MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp
YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa
ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz
SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf
iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X
ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3
IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS
VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE
SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu
+Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt
8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L
HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt
zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P
AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c
mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ
YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52
gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA
Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB
JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX
DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui
TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5
dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65
LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp
0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY
QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL
-----END CERTIFICATE-----
# Issuer: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation
# Subject: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation
# Label: "SSL.com TLS RSA Root CA 2022"
# Serial: 148535279242832292258835760425842727825
# MD5 Fingerprint: d8:4e:c6:59:30:d8:fe:a0:d6:7a:5a:2c:2c:69:78:da
# SHA1 Fingerprint: ec:2c:83:40:72:af:26:95:10:ff:0e:f2:03:ee:31:70:f6:78:9d:ca
# SHA256 Fingerprint: 8f:af:7d:2e:2c:b4:70:9b:b8:e0:b3:36:66:bf:75:a5:dd:45:b5:de:48:0f:8e:a8:d4:bf:e6:be:bc:17:f2:ed
-----BEGIN CERTIFICATE-----
MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO
MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD
DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX
DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw
b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP
L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY
t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins
S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3
PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO
L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3
R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w
dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS
+YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS
d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG
AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f
gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z
NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt
hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM
QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf
R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ
DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW
P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy
lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq
bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w
AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q
r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji
Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU
98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=
-----END CERTIFICATE-----
# Issuer: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation
# Subject: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation
# Label: "SSL.com TLS ECC Root CA 2022"
# Serial: 26605119622390491762507526719404364228
# MD5 Fingerprint: 99:d7:5c:f1:51:36:cc:e9:ce:d9:19:2e:77:71:56:c5
# SHA1 Fingerprint: 9f:5f:d9:1a:54:6d:f5:0c:71:f0:ee:7a:bd:17:49:98:84:73:e2:39
# SHA256 Fingerprint: c3:2f:fd:9f:46:f9:36:d1:6c:36:73:99:09:59:43:4b:9a:d6:0a:af:bb:9e:7c:f3:36:54:f1:44:cc:1b:a1:43
-----BEGIN CERTIFICATE-----
MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw
CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT
U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2
MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh
dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG
ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm
acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN
SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME
GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW
uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp
15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN
b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g==
-----END CERTIFICATE-----
# Issuer: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos
# Subject: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos
# Label: "Atos TrustedRoot Root CA ECC TLS 2021"
# Serial: 81873346711060652204712539181482831616
# MD5 Fingerprint: 16:9f:ad:f1:70:ad:79:d6:ed:29:b4:d1:c5:79:70:a8
# SHA1 Fingerprint: 9e:bc:75:10:42:b3:02:f3:81:f4:f7:30:62:d4:8f:c3:a7:51:b2:dd
# SHA256 Fingerprint: b2:fa:e5:3e:14:cc:d7:ab:92:12:06:47:01:ae:27:9c:1d:89:88:fa:cb:77:5f:a8:a0:08:91:4e:66:39:88:a8
-----BEGIN CERTIFICATE-----
MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w
LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w
CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0
MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF
Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI
zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X
tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4
AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2
KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD
aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu
CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo
9H1/IISpQuQo
-----END CERTIFICATE-----
# Issuer: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos
# Subject: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos
# Label: "Atos TrustedRoot Root CA RSA TLS 2021"
# Serial: 111436099570196163832749341232207667876
# MD5 Fingerprint: d4:d3:46:b8:9a:c0:9c:76:5d:9e:3a:c3:b9:99:31:d2
# SHA1 Fingerprint: 18:52:3b:0d:06:37:e4:d6:3a:df:23:e4:98:fb:5b:16:fb:86:74:48
# SHA256 Fingerprint: 81:a9:08:8e:a5:9f:b3:64:c5:48:a6:f8:55:59:09:9b:6f:04:05:ef:bf:18:e5:32:4e:c9:f4:57:ba:00:11:2f
-----BEGIN CERTIFICATE-----
MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM
MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx
MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00
MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD
QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z
4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv
Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ
kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs
GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln
nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh
3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD
0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy
geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8
ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB
c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI
pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS
4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs
o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ
qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw
xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM
rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4
AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR
0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY
o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5
dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE
oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ==
-----END CERTIFICATE-----
# Issuer: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc.
# Subject: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc.
# Label: "TrustAsia Global Root CA G3"
# Serial: 576386314500428537169965010905813481816650257167
# MD5 Fingerprint: 30:42:1b:b7:bb:81:75:35:e4:16:4f:53:d2:94:de:04
# SHA1 Fingerprint: 63:cf:b6:c1:27:2b:56:e4:88:8e:1c:23:9a:b6:2e:81:47:24:c3:c7
# SHA256 Fingerprint: e0:d3:22:6a:eb:11:63:c2:e4:8f:f9:be:3b:50:b4:c6:43:1b:e7:bb:1e:ac:c5:c3:6b:5d:5e:c5:09:03:9a:08
-----BEGIN CERTIFICATE-----
MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM
BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp
ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe
Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw
IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU
cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS
T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK
AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1
nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep
qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA
yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs
hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX
zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv
kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT
f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA
uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB
o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih
MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E
BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4
wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2
XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1
JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j
ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV
VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx
xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on
AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d
7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj
gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV
+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo
FGWsJwt0ivKH
-----END CERTIFICATE-----
# Issuer: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc.
# Subject: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc.
# Label: "TrustAsia Global Root CA G4"
# Serial: 451799571007117016466790293371524403291602933463
# MD5 Fingerprint: 54:dd:b2:d7:5f:d8:3e:ed:7c:e0:0b:2e:cc:ed:eb:eb
# SHA1 Fingerprint: 57:73:a5:61:5d:80:b2:e6:ac:38:82:fc:68:07:31:ac:9f:b5:92:5a
# SHA256 Fingerprint: be:4b:56:cb:50:56:c0:13:6a:52:6d:f4:44:50:8d:aa:36:a0:b5:4f:42:e4:ac:38:f7:2a:f4:70:e4:79:65:4c
-----BEGIN CERTIFICATE-----
MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw
WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs
IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y
MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD
VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz
dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx
s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw
LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij
YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD
pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE
AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR
UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj
/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA==
-----END CERTIFICATE-----
# Issuer: CN=CommScope Public Trust ECC Root-01 O=CommScope
# Subject: CN=CommScope Public Trust ECC Root-01 O=CommScope
# Label: "CommScope Public Trust ECC Root-01"
# Serial: 385011430473757362783587124273108818652468453534
# MD5 Fingerprint: 3a:40:a7:fc:03:8c:9c:38:79:2f:3a:a2:6c:b6:0a:16
# SHA1 Fingerprint: 07:86:c0:d8:dd:8e:c0:80:98:06:98:d0:58:7a:ef:de:a6:cc:a2:5d
# SHA256 Fingerprint: 11:43:7c:da:7b:b4:5e:41:36:5f:45:b3:9a:38:98:6b:0d:e0:0d:ef:34:8e:0c:7b:b0:87:36:33:80:0b:c3:8b
-----BEGIN CERTIFICATE-----
MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMw
TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t
bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNa
Fw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv
cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDEw
djAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLxeP0C
flfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJE
hRGnSjot6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq
hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg
2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uS
Um9poIyNStDuiw7LR47QjRE=
-----END CERTIFICATE-----
# Issuer: CN=CommScope Public Trust ECC Root-02 O=CommScope
# Subject: CN=CommScope Public Trust ECC Root-02 O=CommScope
# Label: "CommScope Public Trust ECC Root-02"
# Serial: 234015080301808452132356021271193974922492992893
# MD5 Fingerprint: 59:b0:44:d5:65:4d:b8:5c:55:19:92:02:b6:d1:94:b2
# SHA1 Fingerprint: 3c:3f:ef:57:0f:fe:65:93:86:9e:a0:fe:b0:f6:ed:8e:d1:13:c7:e5
# SHA256 Fingerprint: 2f:fb:7f:81:3b:bb:b3:c8:9a:b4:e8:16:2d:0f:16:d7:15:09:a8:30:cc:9d:73:c2:62:e5:14:08:75:d1:ad:4a
-----BEGIN CERTIFICATE-----
MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMw
TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t
bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRa
Fw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv
cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDIw
djAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/MMDAL
j2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmU
v4RDsNuESgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq
hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/n
ich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AV
mkzw5l4lIhVtwodZ0LKOag==
-----END CERTIFICATE-----
# Issuer: CN=CommScope Public Trust RSA Root-01 O=CommScope
# Subject: CN=CommScope Public Trust RSA Root-01 O=CommScope
# Label: "CommScope Public Trust RSA Root-01"
# Serial: 354030733275608256394402989253558293562031411421
# MD5 Fingerprint: 0e:b4:15:bc:87:63:5d:5d:02:73:d4:26:38:68:73:d8
# SHA1 Fingerprint: 6d:0a:5f:f7:b4:23:06:b4:85:b3:b7:97:64:fc:ac:75:f5:33:f2:93
# SHA256 Fingerprint: 02:bd:f9:6e:2a:45:dd:9b:f1:8f:c7:e1:db:df:21:a0:37:9b:a3:c9:c2:61:03:44:cf:d8:d6:06:fe:c1:ed:81
-----BEGIN CERTIFICATE-----
MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQEL
BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi
Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1
NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t
U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt
MDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45FtnYSk
YZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslh
suitQDy6uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0al
DrJLpA6lfO741GIDuZNqihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3Oj
WiE260f6GBfZumbCk6SP/F2krfxQapWsvCQz0b2If4b19bJzKo98rwjyGpg/qYFl
P8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/cZip8UlF1y5mO6D1cv547
KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTifBSeolz7p
UcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/
kQO9lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JO
Hg9O5j9ZpSPcPYeoKFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkB
Ea801M/XrmLTBQe0MXXgDW1XT2mH+VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6U
CBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm45P3luG0wDQYJ
KoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6
NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQ
nmhUQo8mUuJM3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+
QgvfKNmwrZggvkN80V4aCRckjXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2v
trV0KnahP/t1MJ+UXjulYPPLXAziDslg+MkfFoom3ecnf+slpoq9uC02EJqxWE2a
aE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/WNyVntHKLr4W96ioD
j8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+o/E4
Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0w
lREQKC6/oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHn
YfkUyq+Dj7+vsQpZXdxc1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVoc
icCMb3SgazNNtQEo/a2tiRc7ppqEvOuM6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw
-----END CERTIFICATE-----
# Issuer: CN=CommScope Public Trust RSA Root-02 O=CommScope
# Subject: CN=CommScope Public Trust RSA Root-02 O=CommScope
# Label: "CommScope Public Trust RSA Root-02"
# Serial: 480062499834624527752716769107743131258796508494
# MD5 Fingerprint: e1:29:f9:62:7b:76:e2:96:6d:f3:d4:d7:0f:ae:1f:aa
# SHA1 Fingerprint: ea:b0:e2:52:1b:89:93:4c:11:68:f2:d8:9a:ac:22:4c:a3:8a:57:ae
# SHA256 Fingerprint: ff:e9:43:d7:93:42:4b:4f:7c:44:0c:1c:3d:64:8d:53:63:f3:4b:82:dc:87:aa:7a:9f:11:8f:c5:de:e1:01:f1
-----BEGIN CERTIFICATE-----
MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQEL
BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi
Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2
NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t
U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt
MDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3VrCLE
NQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0
kyI9p+Kx7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1C
rWDaSWqVcN3SAOLMV2MCe5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxz
hkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2WWy09X6GDRl224yW4fKcZgBzqZUPckXk2
LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rpM9kzXzehxfCrPfp4sOcs
n/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIfhs1w/tku
FT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5
kQMreyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3
wNemKfrb3vOTlycEVS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6v
wQcQeKwRoi9C8DfF8rhW3Q5iLc4tVn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs
5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7GxcJXvYXowDQYJ
KoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB
KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3
+VGXu6TwYofF1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbyme
APnCKfWxkxlSaRosTKCL4BWaMS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3Nyq
pgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xdgSGn2rtO/+YHqP65DSdsu3BaVXoT
6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2OHG1QAk8mGEPej1WF
sQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+NmYWvt
PjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2d
lklyALKrdVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670
v64fG9PiO/yzcnMcmyiQiRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17O
rg3bhzjlP1v9mxnhMUF6cKojawHhRUzNlM47ni3niAIi9G7oyOzWPPO5std3eqx7
-----END CERTIFICATE-----

View file

@ -60,6 +60,7 @@ __all__ = [
'clear_overloads',
'dataclass_transform',
'deprecated',
'Doc',
'get_overloads',
'final',
'get_args',
@ -248,32 +249,7 @@ class _ExtensionsSpecialForm(typing._SpecialForm, _root=True):
return 'typing_extensions.' + self._name
# On older versions of typing there is an internal class named "Final".
# 3.8+
if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7):
Final = typing.Final
# 3.7
else:
class _FinalForm(_ExtensionsSpecialForm, _root=True):
def __getitem__(self, parameters):
item = typing._type_check(parameters,
f'{self._name} accepts only a single type.')
return typing._GenericAlias(self, (item,))
Final = _FinalForm('Final',
doc="""A special typing construct to indicate that a name
cannot be re-assigned or overridden in a subclass.
For example:
MAX_SIZE: Final = 9000
MAX_SIZE += 1 # Error reported by type checker
class Connection:
TIMEOUT: Final[int] = 10
class FastConnector(Connection):
TIMEOUT = 1 # Error reported by type checker
There is no runtime checking of these properties.""")
if sys.version_info >= (3, 11):
final = typing.final
@ -465,8 +441,6 @@ Type = typing.Type
# Various ABCs mimicking those in collections.abc.
# A few are simply re-exported for completeness.
Awaitable = typing.Awaitable
Coroutine = typing.Coroutine
AsyncIterable = typing.AsyncIterable
@ -475,14 +449,7 @@ Deque = typing.Deque
ContextManager = typing.ContextManager
AsyncContextManager = typing.AsyncContextManager
DefaultDict = typing.DefaultDict
# 3.7.2+
if hasattr(typing, 'OrderedDict'):
OrderedDict = typing.OrderedDict
# 3.7.0-3.7.2
else:
OrderedDict = typing._alias(collections.OrderedDict, (KT, VT))
Counter = typing.Counter
ChainMap = typing.ChainMap
AsyncGenerator = typing.AsyncGenerator
@ -508,12 +475,6 @@ _EXCLUDED_ATTRS = {
"__protocol_attrs__", "__callable_proto_members_only__",
}
if sys.version_info < (3, 8):
_EXCLUDED_ATTRS |= {
"_gorg", "__next_in_mro__", "__extra__", "__tree_hash__", "__args__",
"__origin__"
}
if sys.version_info >= (3, 9):
_EXCLUDED_ATTRS.add("__class_getitem__")
@ -535,46 +496,6 @@ def _get_protocol_attrs(cls):
return attrs
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 = _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)
def _caller(depth=2):
try:
return sys._getframe(depth).f_globals.get('__name__', '__main__')
@ -598,17 +519,10 @@ else:
if type(self)._is_protocol:
raise TypeError('Protocols cannot be instantiated')
if sys.version_info >= (3, 8):
# Inheriting from typing._ProtocolMeta isn't actually desirable,
# but is necessary to allow typing.Protocol and typing_extensions.Protocol
# to mix without getting TypeErrors about "metaclass conflict"
_typing_Protocol = typing.Protocol
_ProtocolMetaBase = type(_typing_Protocol)
else:
_typing_Protocol = _marker
_ProtocolMetaBase = abc.ABCMeta
class _ProtocolMeta(_ProtocolMetaBase):
class _ProtocolMeta(type(typing.Protocol)):
# This metaclass is somewhat unfortunate,
# but is necessary for several reasons...
#
@ -618,10 +532,10 @@ else:
def __new__(mcls, name, bases, namespace, **kwargs):
if name == "Protocol" and len(bases) < 2:
pass
elif {Protocol, _typing_Protocol} & set(bases):
elif {Protocol, typing.Protocol} & set(bases):
for base in bases:
if not (
base in {object, typing.Generic, Protocol, _typing_Protocol}
base in {object, typing.Generic, Protocol, typing.Protocol}
or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, [])
or is_protocol(base)
):
@ -699,12 +613,10 @@ else:
def __eq__(cls, other):
# Hack so that typing.Generic.__class_getitem__
# treats typing_extensions.Protocol
# as equivalent to typing.Protocol on Python 3.8+
# as equivalent to typing.Protocol
if abc.ABCMeta.__eq__(cls, other) is True:
return True
return (
cls is Protocol and other is getattr(typing, "Protocol", object())
)
return cls is Protocol and other is typing.Protocol
# This has to be defined, or the abc-module cache
# complains about classes with this metaclass being unhashable,
@ -737,7 +649,6 @@ else:
return NotImplemented
return True
if sys.version_info >= (3, 8):
class Protocol(typing.Generic, metaclass=_ProtocolMeta):
__doc__ = typing.Protocol.__doc__
__slots__ = ()
@ -759,124 +670,12 @@ else:
if cls._is_protocol and cls.__init__ is Protocol.__init__:
cls.__init__ = _no_init
else:
class Protocol(metaclass=_ProtocolMeta):
# There is quite a lot of overlapping code with typing.Generic.
# Unfortunately it is hard to avoid this on Python <3.8,
# as the typing module on Python 3.7 doesn't let us subclass typing.Generic!
"""Base class for protocol classes. Protocol classes are defined as::
class Proto(Protocol):
def meth(self) -> int:
...
Such classes are primarily used with static type checkers that recognize
structural subtyping (static duck-typing), for example::
class C:
def meth(self) -> int:
return 0
def func(x: Proto) -> int:
return x.meth()
func(C()) # Passes static type check
See PEP 544 for details. Protocol classes decorated with
@typing_extensions.runtime_checkable act
as simple-minded runtime-checkable protocols that check
only the presence of given attributes, ignoring their type signatures.
Protocol classes can be generic, they are defined as::
class GenProto(Protocol[T]):
def meth(self) -> T:
...
"""
__slots__ = ()
_is_protocol = True
_is_runtime_protocol = False
def __new__(cls, *args, **kwds):
if cls is Protocol:
raise TypeError("Type Protocol cannot be instantiated; "
"it can only be used as a base class")
return super().__new__(cls)
@typing._tp_cache
def __class_getitem__(cls, params):
if not isinstance(params, tuple):
params = (params,)
if not params and cls is not typing.Tuple:
raise TypeError(
f"Parameter list to {cls.__qualname__}[...] cannot be empty")
msg = "Parameters to generic types must be types."
params = tuple(typing._type_check(p, msg) for p in params)
if cls is Protocol:
# Generic can only be subscripted with unique type variables.
if not all(isinstance(p, typing.TypeVar) for p in params):
i = 0
while isinstance(params[i], typing.TypeVar):
i += 1
raise TypeError(
"Parameters to Protocol[...] must all be type variables."
f" Parameter {i + 1} is {params[i]}")
if len(set(params)) != len(params):
raise TypeError(
"Parameters to Protocol[...] must all be unique")
else:
# Subscripting a regular Generic subclass.
_check_generic(cls, params, len(cls.__parameters__))
return typing._GenericAlias(cls, params)
def __init_subclass__(cls, *args, **kwargs):
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")
_maybe_adjust_parameters(cls)
# Determine if this is a protocol or a concrete subclass.
if not cls.__dict__.get('_is_protocol', None):
cls._is_protocol = any(b is Protocol for b in cls.__bases__)
# Set (or override) the protocol subclass hook.
if '__subclasshook__' not in cls.__dict__:
cls.__subclasshook__ = _proto_hook
# Prohibit instantiation for protocol classes
if cls._is_protocol and cls.__init__ is Protocol.__init__:
cls.__init__ = _no_init
# The "runtime" alias exists for backwards compatibility.
runtime = runtime_checkable = typing.runtime_checkable
if sys.version_info >= (3, 8):
runtime_checkable = typing.runtime_checkable
else:
def runtime_checkable(cls):
"""Mark a protocol class as a runtime protocol, so that it
can be used with isinstance() and issubclass(). Raise TypeError
if applied to a non-protocol class.
This allows a simple-minded structural check very similar to the
one-offs in collections.abc such as Hashable.
"""
if not (
(isinstance(cls, _ProtocolMeta) or issubclass(cls, typing.Generic))
and getattr(cls, "_is_protocol", False)
):
raise TypeError('@runtime_checkable can be only applied to protocol classes,'
f' got {cls!r}')
cls._is_runtime_protocol = True
return cls
# Exists for backwards compatibility.
runtime = runtime_checkable
# Our version of runtime-checkable protocols is faster on Python 3.7-3.11
# Our version of runtime-checkable protocols is faster on Python 3.8-3.11
if sys.version_info >= (3, 12):
SupportsInt = typing.SupportsInt
SupportsFloat = typing.SupportsFloat
@ -986,11 +785,6 @@ else:
# 3.10.0 and later
_TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters
if sys.version_info >= (3, 8):
_fake_name = "Protocol"
else:
_fake_name = "_Protocol"
class _TypedDictMeta(type):
def __new__(cls, name, bases, ns, total=True):
"""Create new typed dict class object.
@ -1011,10 +805,10 @@ else:
generic_base = ()
# typing.py generally doesn't let you inherit from plain Generic, unless
# the name of the class happens to be "Protocol" (or "_Protocol" on 3.7).
tp_dict = type.__new__(_TypedDictMeta, _fake_name, (*generic_base, dict), ns)
# the name of the class happens to be "Protocol"
tp_dict = type.__new__(_TypedDictMeta, "Protocol", (*generic_base, dict), ns)
tp_dict.__name__ = name
if tp_dict.__qualname__ == _fake_name:
if tp_dict.__qualname__ == "Protocol":
tp_dict.__qualname__ = name
if not hasattr(tp_dict, '__orig_bases__'):
@ -1077,7 +871,7 @@ else:
_TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {})
@_ensure_subclassable(lambda bases: (_TypedDict,))
def TypedDict(__typename, __fields=_marker, *, total=True, **kwargs):
def TypedDict(typename, fields=_marker, /, *, total=True, **kwargs):
"""A simple typed namespace. At runtime it is equivalent to a plain dict.
TypedDict creates a dictionary type such that a type checker will expect all
@ -1124,20 +918,20 @@ else:
See PEP 655 for more details on Required and NotRequired.
"""
if __fields is _marker or __fields is None:
if __fields is _marker:
if fields is _marker or fields is None:
if fields is _marker:
deprecated_thing = "Failing to pass a value for the 'fields' parameter"
else:
deprecated_thing = "Passing `None` as the 'fields' parameter"
example = f"`{__typename} = TypedDict({__typename!r}, {{}})`"
example = f"`{typename} = TypedDict({typename!r}, {{}})`"
deprecation_msg = (
f"{deprecated_thing} is deprecated and will be disallowed in "
"Python 3.15. To create a TypedDict class with 0 fields "
"using the functional syntax, pass an empty dictionary, e.g. "
) + example + "."
warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2)
__fields = kwargs
fields = kwargs
elif kwargs:
raise TypeError("TypedDict takes either a dict or keyword arguments,"
" but not both")
@ -1150,13 +944,13 @@ else:
stacklevel=2,
)
ns = {'__annotations__': dict(__fields)}
ns = {'__annotations__': dict(fields)}
module = _caller()
if module is not None:
# Setting correct module is necessary to make typed dict classes pickleable.
ns['__module__'] = module
td = _TypedDictMeta(__typename, (), ns, total=total)
td = _TypedDictMeta(typename, (), ns, total=total)
td.__orig_bases__ = (TypedDict,)
return td
@ -1186,7 +980,7 @@ if hasattr(typing, "assert_type"):
assert_type = typing.assert_type
else:
def assert_type(__val, __typ):
def assert_type(val, typ, /):
"""Assert (to the type checker) that the value is of the given type.
When the type checker encounters a call to assert_type(), it
@ -1199,12 +993,12 @@ else:
At runtime this returns the first argument unchanged and otherwise
does nothing.
"""
return __val
return val
if hasattr(typing, "Required"):
if hasattr(typing, "Required"): # 3.11+
get_type_hints = typing.get_type_hints
else:
else: # <=3.10
# replaces _strip_annotations()
def _strip_extras(t):
"""Strips Annotated, Required and NotRequired from a given type."""
@ -1262,11 +1056,11 @@ else:
- If two dict arguments are passed, they specify globals and
locals, respectively.
"""
if hasattr(typing, "Annotated"):
if hasattr(typing, "Annotated"): # 3.9+
hint = typing.get_type_hints(
obj, globalns=globalns, localns=localns, include_extras=True
)
else:
else: # 3.8
hint = typing.get_type_hints(obj, globalns=globalns, localns=localns)
if include_extras:
return hint
@ -1279,7 +1073,7 @@ if hasattr(typing, 'Annotated'):
# Not exported and not a public API, but needed for get_origin() and get_args()
# to work.
_AnnotatedAlias = typing._AnnotatedAlias
# 3.7-3.8
# 3.8
else:
class _AnnotatedAlias(typing._GenericAlias, _root=True):
"""Runtime representation of an annotated type.
@ -1384,7 +1178,7 @@ else:
if sys.version_info[:2] >= (3, 10):
get_origin = typing.get_origin
get_args = typing.get_args
# 3.7-3.9
# 3.8-3.9
else:
try:
# 3.9+
@ -1462,7 +1256,7 @@ elif sys.version_info[:2] >= (3, 9):
It's invalid when used anywhere except as in the example above.
"""
raise TypeError(f"{self} is not subscriptable")
# 3.7-3.8
# 3.8
else:
TypeAlias = _ExtensionsSpecialForm(
'TypeAlias',
@ -1484,6 +1278,9 @@ def _set_default(type_param, default):
type_param.__default__ = tuple((typing._type_check(d, "Default must be a type")
for d in default))
elif default != _marker:
if isinstance(type_param, ParamSpec) and default is ...: # ... not valid <3.11
type_param.__default__ = default
else:
type_param.__default__ = typing._type_check(default, "Default must be a type")
else:
type_param.__default__ = None
@ -1519,7 +1316,7 @@ class TypeVar(metaclass=_TypeVarLikeMeta):
covariant=False, contravariant=False,
default=_marker, infer_variance=False):
if hasattr(typing, "TypeAliasType"):
# PEP 695 implemented, can pass infer_variance to typing.TypeVar
# PEP 695 implemented (3.12+), can pass infer_variance to typing.TypeVar
typevar = typing.TypeVar(name, *constraints, bound=bound,
covariant=covariant, contravariant=contravariant,
infer_variance=infer_variance)
@ -1541,7 +1338,7 @@ class TypeVar(metaclass=_TypeVarLikeMeta):
if hasattr(typing, 'ParamSpecArgs'):
ParamSpecArgs = typing.ParamSpecArgs
ParamSpecKwargs = typing.ParamSpecKwargs
# 3.7-3.9
# 3.8-3.9
else:
class _Immutable:
"""Mixin to indicate that object should not be copied."""
@ -1630,7 +1427,7 @@ if hasattr(typing, 'ParamSpec'):
def __init_subclass__(cls) -> None:
raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type")
# 3.7-3.9
# 3.8-3.9
else:
# Inherits from list as a workaround for Callable checks in Python < 3.9.2.
@ -1735,7 +1532,7 @@ else:
pass
# 3.7-3.9
# 3.8-3.9
if not hasattr(typing, 'Concatenate'):
# Inherits from list as a workaround for Callable checks in Python < 3.9.2.
class _ConcatenateGenericAlias(list):
@ -1770,7 +1567,7 @@ if not hasattr(typing, 'Concatenate'):
)
# 3.7-3.9
# 3.8-3.9
@typing._tp_cache
def _concatenate_getitem(self, parameters):
if parameters == ():
@ -1804,7 +1601,7 @@ elif sys.version_info[:2] >= (3, 9):
See PEP 612 for detailed information.
"""
return _concatenate_getitem(self, parameters)
# 3.7-8
# 3.8
else:
class _ConcatenateForm(_ExtensionsSpecialForm, _root=True):
def __getitem__(self, parameters):
@ -1874,7 +1671,7 @@ elif sys.version_info[:2] >= (3, 9):
"""
item = typing._type_check(parameters, f'{self} accepts only a single type.')
return typing._GenericAlias(self, (item,))
# 3.7-3.8
# 3.8
else:
class _TypeGuardForm(_ExtensionsSpecialForm, _root=True):
def __getitem__(self, parameters):
@ -1972,7 +1769,7 @@ class _SpecialForm(typing._Final, _root=True):
return self._getitem(self, parameters)
if hasattr(typing, "LiteralString"):
if hasattr(typing, "LiteralString"): # 3.11+
LiteralString = typing.LiteralString
else:
@_SpecialForm
@ -1995,7 +1792,7 @@ else:
raise TypeError(f"{self} is not subscriptable")
if hasattr(typing, "Self"):
if hasattr(typing, "Self"): # 3.11+
Self = typing.Self
else:
@_SpecialForm
@ -2016,7 +1813,7 @@ else:
raise TypeError(f"{self} is not subscriptable")
if hasattr(typing, "Never"):
if hasattr(typing, "Never"): # 3.11+
Never = typing.Never
else:
@_SpecialForm
@ -2046,10 +1843,10 @@ else:
raise TypeError(f"{self} is not subscriptable")
if hasattr(typing, 'Required'):
if hasattr(typing, 'Required'): # 3.11+
Required = typing.Required
NotRequired = typing.NotRequired
elif sys.version_info[:2] >= (3, 9):
elif sys.version_info[:2] >= (3, 9): # 3.9-3.10
@_ExtensionsSpecialForm
def Required(self, parameters):
"""A special typing construct to mark a key of a total=False TypedDict
@ -2087,7 +1884,7 @@ elif sys.version_info[:2] >= (3, 9):
item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
return typing._GenericAlias(self, (item,))
else:
else: # 3.8
class _RequiredForm(_ExtensionsSpecialForm, _root=True):
def __getitem__(self, parameters):
item = typing._type_check(parameters,
@ -2175,7 +1972,7 @@ if sys.version_info >= (3, 12): # PEP 692 changed the repr of Unpack[]
def _is_unpack(obj):
return get_origin(obj) is Unpack
elif sys.version_info[:2] >= (3, 9):
elif sys.version_info[:2] >= (3, 9): # 3.9+
class _UnpackSpecialForm(_ExtensionsSpecialForm, _root=True):
def __init__(self, getitem):
super().__init__(getitem)
@ -2192,7 +1989,7 @@ elif sys.version_info[:2] >= (3, 9):
def _is_unpack(obj):
return isinstance(obj, _UnpackAlias)
else:
else: # 3.8
class _UnpackAlias(typing._GenericAlias, _root=True):
__class__ = typing.TypeVar
@ -2225,7 +2022,7 @@ if hasattr(typing, "TypeVarTuple"): # 3.11+
def __init_subclass__(self, *args, **kwds):
raise TypeError("Cannot subclass special typing classes")
else:
else: # <=3.10
class TypeVarTuple(_DefaultMixin):
"""Type variable tuple.
@ -2304,10 +2101,10 @@ else:
raise TypeError("Cannot subclass special typing classes")
if hasattr(typing, "reveal_type"):
if hasattr(typing, "reveal_type"): # 3.11+
reveal_type = typing.reveal_type
else:
def reveal_type(__obj: T) -> T:
else: # <=3.10
def reveal_type(obj: T, /) -> T:
"""Reveal the inferred type of a variable.
When a static type checker encounters a call to ``reveal_type()``,
@ -2323,14 +2120,14 @@ else:
argument and returns it unchanged.
"""
print(f"Runtime type is {type(__obj).__name__!r}", file=sys.stderr)
return __obj
print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr)
return obj
if hasattr(typing, "assert_never"):
if hasattr(typing, "assert_never"): # 3.11+
assert_never = typing.assert_never
else:
def assert_never(__arg: Never) -> Never:
else: # <=3.10
def assert_never(arg: Never, /) -> Never:
"""Assert to the type checker that a line of code is unreachable.
Example::
@ -2353,10 +2150,10 @@ else:
raise AssertionError("Expected code to be unreachable")
if sys.version_info >= (3, 12):
if sys.version_info >= (3, 12): # 3.12+
# dataclass_transform exists in 3.11 but lacks the frozen_default parameter
dataclass_transform = typing.dataclass_transform
else:
else: # <=3.11
def dataclass_transform(
*,
eq_default: bool = True,
@ -2443,12 +2240,12 @@ else:
return decorator
if hasattr(typing, "override"):
if hasattr(typing, "override"): # 3.12+
override = typing.override
else:
else: # <=3.11
_F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any])
def override(__arg: _F) -> _F:
def override(arg: _F, /) -> _F:
"""Indicate that a method is intended to override a method in a base class.
Usage:
@ -2475,13 +2272,13 @@ else:
"""
try:
__arg.__override__ = True
arg.__override__ = True
except (AttributeError, TypeError):
# Skip the attribute silently if it is not writable.
# AttributeError happens if the object has __slots__ or a
# read-only property, TypeError if it's a builtin class.
pass
return __arg
return arg
if hasattr(typing, "deprecated"):
@ -2490,7 +2287,8 @@ else:
_T = typing.TypeVar("_T")
def deprecated(
__msg: str,
msg: str,
/,
*,
category: typing.Optional[typing.Type[Warning]] = DeprecationWarning,
stacklevel: int = 1,
@ -2533,17 +2331,17 @@ else:
See PEP 702 for details.
"""
def decorator(__arg: _T) -> _T:
def decorator(arg: _T, /) -> _T:
if category is None:
__arg.__deprecated__ = __msg
return __arg
elif isinstance(__arg, type):
original_new = __arg.__new__
has_init = __arg.__init__ is not object.__init__
arg.__deprecated__ = msg
return arg
elif isinstance(arg, type):
original_new = arg.__new__
has_init = arg.__init__ is not object.__init__
@functools.wraps(original_new)
def __new__(cls, *args, **kwargs):
warnings.warn(__msg, category=category, stacklevel=stacklevel + 1)
warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
if original_new is not object.__new__:
return original_new(cls, *args, **kwargs)
# Mirrors a similar check in object.__new__.
@ -2552,21 +2350,21 @@ else:
else:
return original_new(cls)
__arg.__new__ = staticmethod(__new__)
__arg.__deprecated__ = __new__.__deprecated__ = __msg
return __arg
elif callable(__arg):
@functools.wraps(__arg)
arg.__new__ = staticmethod(__new__)
arg.__deprecated__ = __new__.__deprecated__ = msg
return arg
elif callable(arg):
@functools.wraps(arg)
def wrapper(*args, **kwargs):
warnings.warn(__msg, category=category, stacklevel=stacklevel + 1)
return __arg(*args, **kwargs)
warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
return arg(*args, **kwargs)
__arg.__deprecated__ = wrapper.__deprecated__ = __msg
arg.__deprecated__ = wrapper.__deprecated__ = msg
return wrapper
else:
raise TypeError(
"@deprecated decorator with non-None category must be applied to "
f"a class or callable, not {__arg!r}"
f"a class or callable, not {arg!r}"
)
return decorator
@ -2584,7 +2382,7 @@ if not hasattr(typing, "TypeVarTuple"):
typing._check_generic = _check_generic
# Backport typing.NamedTuple as it exists in Python 3.12.
# Backport typing.NamedTuple as it exists in Python 3.13.
# 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.
# On 3.12, we added __orig_bases__ to call-based NamedTuples
@ -2655,7 +2453,7 @@ else:
return (_NamedTuple,)
@_ensure_subclassable(_namedtuple_mro_entries)
def NamedTuple(__typename, __fields=_marker, **kwargs):
def NamedTuple(typename, fields=_marker, /, **kwargs):
"""Typed version of namedtuple.
Usage::
@ -2675,7 +2473,7 @@ else:
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
"""
if __fields is _marker:
if fields is _marker:
if kwargs:
deprecated_thing = "Creating NamedTuple classes using keyword arguments"
deprecation_msg = (
@ -2684,14 +2482,14 @@ else:
)
else:
deprecated_thing = "Failing to pass a value for the 'fields' parameter"
example = f"`{__typename} = NamedTuple({__typename!r}, [])`"
example = f"`{typename} = NamedTuple({typename!r}, [])`"
deprecation_msg = (
"{name} is deprecated and will be disallowed in Python {remove}. "
"To create a NamedTuple class with 0 fields "
"using the functional syntax, "
"pass an empty list, e.g. "
) + example + "."
elif __fields is None:
elif fields is None:
if kwargs:
raise TypeError(
"Cannot pass `None` as the 'fields' parameter "
@ -2699,7 +2497,7 @@ else:
)
else:
deprecated_thing = "Passing `None` as the 'fields' parameter"
example = f"`{__typename} = NamedTuple({__typename!r}, [])`"
example = f"`{typename} = NamedTuple({typename!r}, [])`"
deprecation_msg = (
"{name} is deprecated and will be disallowed in Python {remove}. "
"To create a NamedTuple class with 0 fields "
@ -2709,27 +2507,17 @@ else:
elif kwargs:
raise TypeError("Either list of fields or keywords"
" can be provided to NamedTuple, not both")
if __fields is _marker or __fields is None:
if fields is _marker or fields is None:
warnings.warn(
deprecation_msg.format(name=deprecated_thing, remove="3.15"),
DeprecationWarning,
stacklevel=2,
)
__fields = kwargs.items()
nt = _make_nmtuple(__typename, __fields, module=_caller())
fields = kwargs.items()
nt = _make_nmtuple(typename, fields, module=_caller())
nt.__orig_bases__ = (NamedTuple,)
return nt
# 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):
_new_signature = '(typename, fields=None, /, **kwargs)'
if isinstance(NamedTuple, _types.FunctionType):
NamedTuple.__text_signature__ = _new_signature
else:
NamedTuple.__call__.__text_signature__ = _new_signature
if hasattr(collections.abc, "Buffer"):
Buffer = collections.abc.Buffer
@ -2764,7 +2552,7 @@ else:
if hasattr(_types, "get_original_bases"):
get_original_bases = _types.get_original_bases
else:
def get_original_bases(__cls):
def get_original_bases(cls, /):
"""Return the class's "original" bases prior to modification by `__mro_entries__`.
Examples::
@ -2786,13 +2574,10 @@ else:
assert get_original_bases(int) == (object,)
"""
try:
return __cls.__orig_bases__
except AttributeError:
try:
return __cls.__bases__
return cls.__dict__.get("__orig_bases__", cls.__bases__)
except AttributeError:
raise TypeError(
f'Expected an instance of type, not {type(__cls).__name__!r}'
f'Expected an instance of type, not {type(cls).__name__!r}'
) from None
@ -2920,13 +2705,13 @@ else:
# Setting this attribute closes the TypeAliasType from further modification
self.__name__ = name
def __setattr__(self, __name: str, __value: object) -> None:
def __setattr__(self, name: str, value: object, /) -> None:
if hasattr(self, "__name__"):
self._raise_attribute_error(__name)
super().__setattr__(__name, __value)
self._raise_attribute_error(name)
super().__setattr__(name, value)
def __delattr__(self, __name: str) -> Never:
self._raise_attribute_error(__name)
def __delattr__(self, name: str, /) -> Never:
self._raise_attribute_error(name)
def _raise_attribute_error(self, name: str) -> Never:
# Match the Python 3.12 error messages exactly
@ -2987,7 +2772,7 @@ if hasattr(typing, "is_protocol"):
is_protocol = typing.is_protocol
get_protocol_members = typing.get_protocol_members
else:
def is_protocol(__tp: type) -> bool:
def is_protocol(tp: type, /) -> bool:
"""Return True if the given type is a Protocol.
Example::
@ -3002,13 +2787,13 @@ else:
False
"""
return (
isinstance(__tp, type)
and getattr(__tp, '_is_protocol', False)
and __tp is not Protocol
and __tp is not getattr(typing, "Protocol", object())
isinstance(tp, type)
and getattr(tp, '_is_protocol', False)
and tp is not Protocol
and tp is not typing.Protocol
)
def get_protocol_members(__tp: type) -> typing.FrozenSet[str]:
def get_protocol_members(tp: type, /) -> typing.FrozenSet[str]:
"""Return the set of members defined in a Protocol.
Example::
@ -3022,11 +2807,46 @@ else:
Raise a TypeError for arguments that are not Protocols.
"""
if not is_protocol(__tp):
raise TypeError(f'{__tp!r} is not a Protocol')
if hasattr(__tp, '__protocol_attrs__'):
return frozenset(__tp.__protocol_attrs__)
return frozenset(_get_protocol_attrs(__tp))
if not is_protocol(tp):
raise TypeError(f'{tp!r} is not a Protocol')
if hasattr(tp, '__protocol_attrs__'):
return frozenset(tp.__protocol_attrs__)
return frozenset(_get_protocol_attrs(tp))
if hasattr(typing, "Doc"):
Doc = typing.Doc
else:
class Doc:
"""Define the documentation of a type annotation using ``Annotated``, to be
used in class attributes, function and method parameters, return values,
and variables.
The value should be a positional-only string literal to allow static tools
like editors and documentation generators to use it.
This complements docstrings.
The string value passed is available in the attribute ``documentation``.
Example::
>>> from typing_extensions import Annotated, Doc
>>> def hi(to: Annotated[str, Doc("Who to say hi to")]) -> None: ...
"""
def __init__(self, documentation: str, /) -> None:
self.documentation = documentation
def __repr__(self) -> str:
return f"Doc({self.documentation!r})"
def __hash__(self) -> int:
return hash(self.documentation)
def __eq__(self, other: object) -> bool:
if not isinstance(other, Doc):
return NotImplemented
return self.documentation == other.documentation
# Aliases for items that have always been in typing.

View file

@ -27,7 +27,10 @@ from _babase import (
apptime,
apptimer,
AppTimer,
can_toggle_fullscreen,
fullscreen_control_available,
fullscreen_control_get,
fullscreen_control_key_shortcut,
fullscreen_control_set,
charstr,
clipboard_get_text,
clipboard_has_text,
@ -58,10 +61,8 @@ from _babase import (
in_logic_thread,
increment_analytics_count,
is_os_playing_music,
is_running_on_fire_tv,
is_xcode_build,
lock_all_input,
mac_music_app_get_library_source,
mac_music_app_get_playlists,
mac_music_app_get_volume,
mac_music_app_init,
@ -72,7 +73,10 @@ from _babase import (
music_player_set_volume,
music_player_shutdown,
music_player_stop,
native_review_request,
native_review_request_supported,
native_stack_trace,
open_file_externally,
print_load_info,
pushcall,
quit,
@ -82,7 +86,6 @@ from _babase import (
screenmessage,
set_analytics_screen,
set_low_level_config_value,
set_stress_testing,
set_thread_name,
set_ui_input_device,
show_progress_bar,
@ -114,6 +117,11 @@ from babase._apputils import (
AppHealthMonitor,
)
from babase._cloud import CloudSubsystem
from babase._devconsole import (
DevConsoleTab,
DevConsoleTabEntry,
DevConsoleSubsystem,
)
from babase._emptyappmode import EmptyAppMode
from babase._error import (
print_exception,
@ -146,9 +154,8 @@ from babase._general import (
getclass,
get_type_name,
)
from babase._keyboard import Keyboard
from babase._language import Lstr, LanguageSubsystem
from babase._login import LoginAdapter
from babase._login import LoginAdapter, LoginInfo
# noinspection PyProtectedMember
# (PyCharm inspection bug?)
@ -157,6 +164,7 @@ from babase._mgen.enums import (
SpecialChar,
InputType,
UIScale,
QuitType,
)
from babase._math import normalized_color, is_point_in_box, vec3validate
from babase._meta import MetadataSubsystem
@ -194,7 +202,10 @@ __all__ = [
'apptimer',
'AppTimer',
'Call',
'can_toggle_fullscreen',
'fullscreen_control_available',
'fullscreen_control_get',
'fullscreen_control_key_shortcut',
'fullscreen_control_set',
'charstr',
'clipboard_get_text',
'clipboard_has_text',
@ -206,6 +217,9 @@ __all__ = [
'ContextError',
'ContextRef',
'DelegateNotFoundError',
'DevConsoleTab',
'DevConsoleTabEntry',
'DevConsoleSubsystem',
'DisplayTime',
'displaytime',
'displaytimer',
@ -244,14 +258,12 @@ __all__ = [
'is_browser_likely_available',
'is_os_playing_music',
'is_point_in_box',
'is_running_on_fire_tv',
'is_xcode_build',
'Keyboard',
'LanguageSubsystem',
'lock_all_input',
'LoginAdapter',
'LoginInfo',
'Lstr',
'mac_music_app_get_library_source',
'mac_music_app_get_playlists',
'mac_music_app_get_volume',
'mac_music_app_init',
@ -264,10 +276,13 @@ __all__ = [
'music_player_set_volume',
'music_player_shutdown',
'music_player_stop',
'native_review_request',
'native_review_request_supported',
'native_stack_trace',
'NodeNotFoundError',
'normalized_color',
'NotFoundError',
'open_file_externally',
'Permission',
'PlayerNotFoundError',
'Plugin',
@ -278,6 +293,7 @@ __all__ = [
'print_load_info',
'pushcall',
'quit',
'QuitType',
'reload_media',
'request_permission',
'safecolor',
@ -287,7 +303,6 @@ __all__ = [
'SessionTeamNotFoundError',
'set_analytics_screen',
'set_low_level_config_value',
'set_stress_testing',
'set_thread_name',
'set_ui_input_device',
'show_progress_bar',

View file

@ -6,7 +6,7 @@ from __future__ import annotations
import hashlib
import logging
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, assert_never
from efro.call import tpartial
from efro.error import CommunicationError
@ -16,7 +16,7 @@ import _babase
if TYPE_CHECKING:
from typing import Any
from babase._login import LoginAdapter
from babase._login import LoginAdapter, LoginInfo
DEBUG_LOG = False
@ -27,10 +27,12 @@ class AccountV2Subsystem:
Category: **App Classes**
Access the single shared instance of this class at 'ba.app.accounts'.
Access the single shared instance of this class at 'ba.app.plus.accounts'.
"""
def __init__(self) -> None:
from babase._login import LoginAdapterGPGS, LoginAdapterGameCenter
# Whether or not everything related to an initial login
# (or lack thereof) has completed. This includes things like
# workspace syncing. Completion of this is what flips the app
@ -45,16 +47,13 @@ class AccountV2Subsystem:
self._implicit_state_changed = False
self._can_do_auto_sign_in = True
if _babase.app.classic is None:
raise RuntimeError('Needs updating for no-classic case.')
if (
_babase.app.classic.platform == 'android'
and _babase.app.classic.subplatform == 'google'
):
from babase._login import LoginAdapterGPGS
self.login_adapters[LoginType.GPGS] = LoginAdapterGPGS()
adapter: LoginAdapter
if _babase.using_google_play_game_services():
adapter = LoginAdapterGPGS()
self.login_adapters[adapter.login_type] = adapter
if _babase.using_game_center():
adapter = LoginAdapterGameCenter()
self.login_adapters[adapter.login_type] = adapter
def on_app_loading(self) -> None:
"""Should be called at standard on_app_loading time."""
@ -62,10 +61,6 @@ class AccountV2Subsystem:
for adapter in self.login_adapters.values():
adapter.on_app_loading()
def set_primary_credentials(self, credentials: str | None) -> None:
"""Set credentials for the primary app account."""
raise NotImplementedError('This should be overridden.')
def have_primary_credentials(self) -> bool:
"""Are credentials currently set for the primary app account?
@ -80,10 +75,6 @@ class AccountV2Subsystem:
"""The primary account for the app, or None if not logged in."""
return self.do_get_primary()
def do_get_primary(self) -> AccountV2Handle | None:
"""Internal - should be overridden by subclass."""
return None
def on_primary_account_changed(
self, account: AccountV2Handle | None
) -> None:
@ -142,6 +133,8 @@ class AccountV2Subsystem:
"""An implicit sign-in happened (called by native layer)."""
from babase._login import LoginAdapter
assert _babase.in_logic_thread()
with _babase.ContextRef.empty():
self.login_adapters[login_type].set_implicit_login_state(
LoginAdapter.ImplicitLoginState(
@ -151,6 +144,7 @@ class AccountV2Subsystem:
def on_implicit_sign_out(self, login_type: LoginType) -> None:
"""An implicit sign-out happened (called by native layer)."""
assert _babase.in_logic_thread()
with _babase.ContextRef.empty():
self.login_adapters[login_type].set_implicit_login_state(None)
@ -192,9 +186,10 @@ class AccountV2Subsystem:
cfgkey = 'ImplicitLoginStates'
cfgdict = _babase.app.config.setdefault(cfgkey, {})
# Store which (if any) adapter is currently implicitly signed in.
# Making the assumption there will only ever be one implicit
# adapter at a time; may need to update this if that changes.
# Store which (if any) adapter is currently implicitly signed
# in. Making the assumption there will only ever be one implicit
# adapter at a time; may need to revisit this logic if that
# changes.
prev_state = cfgdict.get(login_type.value)
if state is None:
self._implicit_signed_in_adapter = None
@ -205,18 +200,26 @@ class AccountV2Subsystem:
state.login_id
)
# Special case: if the user is already signed in but not with
# this implicit login, we may want to let them know that the
# 'Welcome back FOO' they likely just saw is not actually
# accurate.
# Special case: if the user is already signed in but not
# with this implicit login, let them know that the 'Welcome
# back FOO' they likely just saw is not actually accurate.
if (
self.primary is not None
and not self.login_adapters[login_type].is_back_end_active()
):
service_str: Lstr | None
if login_type is LoginType.GPGS:
service_str = Lstr(resource='googlePlayText')
else:
elif login_type is LoginType.GAME_CENTER:
# Note: Apparently Game Center is just called 'Game
# Center' in all languages. Can revisit if not true.
# https://developer.apple.com/forums/thread/725779
service_str = Lstr(value='Game Center')
elif login_type is LoginType.EMAIL:
# Not possible; just here for exhaustive coverage.
service_str = None
else:
assert_never(login_type)
if service_str is not None:
_babase.apptimer(
2.0,
@ -259,6 +262,14 @@ class AccountV2Subsystem:
# We may want to auto-sign-in based on this new state.
self._update_auto_sign_in()
def do_get_primary(self) -> AccountV2Handle | None:
"""Internal - should be overridden by subclass."""
raise NotImplementedError('This should be overridden.')
def set_primary_credentials(self, credentials: str | None) -> None:
"""Set credentials for the primary app account."""
raise NotImplementedError('This should be overridden.')
def _update_auto_sign_in(self) -> None:
plus = _babase.app.plus
assert plus is not None
@ -266,7 +277,7 @@ class AccountV2Subsystem:
# If implicit state has changed, try to respond.
if self._implicit_state_changed:
if self._implicit_signed_in_adapter is None:
# If implicit back-end is signed out, follow suit
# If implicit back-end has signed out, we follow suit
# immediately; no need to wait for network connectivity.
if DEBUG_LOG:
logging.debug(
@ -286,9 +297,8 @@ class AccountV2Subsystem:
# Consider this an 'explicit' sign in because the
# implicit-login state change presumably was triggered
# by some user action (signing in, signing out, or
# switching accounts via the back-end).
# NOTE: should test case where we don't have
# connectivity here.
# switching accounts via the back-end). NOTE: should
# test case where we don't have connectivity here.
if plus.cloud.is_connected():
if DEBUG_LOG:
logging.debug(
@ -419,14 +429,11 @@ class AccountV2Handle:
used with some operations such as cloud messaging.
"""
def __init__(self) -> None:
self.tag = '?'
self.workspacename: str | None = None
self.workspaceid: str | None = None
# Login types and their display-names associated with this account.
self.logins: dict[LoginType, str] = {}
accountid: str
tag: str
workspacename: str | None
workspaceid: str | None
logins: dict[LoginType, LoginInfo]
def __enter__(self) -> None:
"""Support for "with" statement.

View file

@ -1,12 +1,10 @@
# Released under the MIT License. See LICENSE for details.
#
"""Functionality related to the high level state of the app."""
# pylint: disable=too-many-lines
from __future__ import annotations
import os
import logging
import warnings
from enum import Enum
from typing import TYPE_CHECKING
from concurrent.futures import ThreadPoolExecutor
@ -24,6 +22,7 @@ from babase._appcomponent import AppComponentSubsystem
from babase._appmodeselector import AppModeSelector
from babase._appintent import AppIntentDefault, AppIntentExec
from babase._stringedit import StringEditSubsystem
from babase._devconsole import DevConsoleSubsystem
if TYPE_CHECKING:
import asyncio
@ -57,6 +56,8 @@ class App:
# pylint: disable=too-many-public-methods
# A few things defined as non-optional values but not actually
# available until the app starts.
plugins: PluginSubsystem
lang: LanguageSubsystem
health_monitor: AppHealthMonitor
@ -71,7 +72,7 @@ class App:
# The app has not yet begun starting and should not be used in
# any way.
NOT_RUNNING = 0
NOT_STARTED = 0
# The native layer is spinning up its machinery (screens,
# renderers, etc.). Nothing should happen in the Python layer
@ -91,13 +92,23 @@ class App:
# All pieces are in place and the app is now doing its thing.
RUNNING = 4
# The app is backgrounded or otherwise suspended.
PAUSED = 5
# Used on platforms such as mobile where the app basically needs
# to shut down while backgrounded. In this state, all event
# loops are suspended and all graphics and audio must cease
# completely. Be aware that the suspended state can be entered
# from any other state including NATIVE_BOOTSTRAPPING and
# SHUTTING_DOWN.
SUSPENDED = 5
# The app is shutting down.
# The app is shutting down. This process may involve sending
# network messages or other things that can take up to a few
# seconds, so ideally graphics and audio should remain
# functional (with fades or spinners or whatever to show
# something is happening).
SHUTTING_DOWN = 6
# The app has completed shutdown.
# The app has completed shutdown. Any code running here should
# be basically immediate.
SHUTDOWN_COMPLETE = 7
class DefaultAppModeSelector(AppModeSelector):
@ -140,9 +151,9 @@ class App:
def __init__(self) -> None:
"""(internal)
Do not instantiate this class; access the single shared instance
of it as 'app' which is available in various Ballistica
feature-set modules such as babase.
Do not instantiate this class. You can access the single shared
instance of it through various high level packages: 'babase.app',
'bascenev1.app', 'bauiv1.app', etc.
"""
# Hack for docs-generation: we can be imported with dummy modules
@ -151,32 +162,35 @@ class App:
return
self.env: babase.Env = _babase.Env()
self.state = self.State.NOT_RUNNING
self.state = self.State.NOT_STARTED
# Default executor which can be used for misc background
# processing. It should also be passed to any additional asyncio
# loops we create so that everything shares the same single set
# of worker threads.
self.threadpool = ThreadPoolExecutor(thread_name_prefix='baworker')
self.threadpool = ThreadPoolExecutor(
thread_name_prefix='baworker',
initializer=self._thread_pool_thread_init,
)
self.meta = MetadataSubsystem()
self.net = NetworkSubsystem()
self.workspaces = WorkspaceSubsystem()
self.components = AppComponentSubsystem()
self.stringedit = StringEditSubsystem()
self.devconsole = DevConsoleSubsystem()
# This is incremented any time the app is backgrounded or
# foregrounded; can be a simple way to determine if network data
# should be refreshed/etc.
self.fg_state = 0
self.config_file_healthy: bool = False
self._subsystems: list[AppSubsystem] = []
self._native_bootstrapping_completed = False
self._init_completed = False
self._meta_scan_completed = False
self._native_start_called = False
self._native_paused = False
self._native_suspended = False
self._native_shutdown_called = False
self._native_shutdown_complete_called = False
self._initial_sign_in_completed = False
@ -194,8 +208,11 @@ class App:
self._mode_selector: babase.AppModeSelector | None = None
self._shutdown_task: asyncio.Task[None] | None = None
self._shutdown_tasks: list[Coroutine[None, None, None]] = [
self._wait_for_shutdown_suppressions()
self._wait_for_shutdown_suppressions(),
self._fade_and_shutdown_graphics(),
self._fade_and_shutdown_audio(),
]
self._pool_thread_count = 0
def postinit(self) -> None:
"""Called after we've been inited and assigned to babase.app.
@ -212,6 +229,15 @@ class App:
self.lang = LanguageSubsystem()
self.plugins = PluginSubsystem()
@property
def active(self) -> bool:
"""Whether the app is currently front and center.
This will be False when the app is hidden, other activities
are covering it, etc. (depending on the platform).
"""
return _babase.app_is_active()
@property
def aioloop(self) -> asyncio.AbstractEventLoop:
"""The logic thread's asyncio event loop.
@ -311,7 +337,7 @@ class App:
def add_shutdown_task(self, coro: Coroutine[None, None, None]) -> None:
"""Add a task to be run on app shutdown.
Note that tasks will be killed after
Note that shutdown tasks will be canceled after
App.SHUTDOWN_TASK_TIMEOUT_SECONDS if they are still running.
"""
if (
@ -385,18 +411,18 @@ class App:
self._native_bootstrapping_completed = True
self._update_state()
def on_native_pause(self) -> None:
"""Called by the native layer when the app pauses."""
def on_native_suspend(self) -> None:
"""Called by the native layer when the app is suspended."""
assert _babase.in_logic_thread()
assert not self._native_paused # Should avoid redundant calls.
self._native_paused = True
assert not self._native_suspended # Should avoid redundant calls.
self._native_suspended = True
self._update_state()
def on_native_resume(self) -> None:
"""Called by the native layer when the app resumes."""
def on_native_unsuspend(self) -> None:
"""Called by the native layer when the app suspension ends."""
assert _babase.in_logic_thread()
assert self._native_paused # Should avoid redundant calls.
self._native_paused = False
assert self._native_suspended # Should avoid redundant calls.
self._native_suspended = False
self._update_state()
def on_native_shutdown(self) -> None:
@ -415,7 +441,7 @@ class App:
"""(internal)"""
from babase._appconfig import read_app_config
self._config, self.config_file_healthy = read_app_config()
self._config = read_app_config()
def handle_deep_link(self, url: str) -> None:
"""Handle a deep link URL."""
@ -493,7 +519,7 @@ class App:
except Exception:
logging.exception('Error setting app intent to %s.', intent)
_babase.pushcall(
tpartial(self._apply_intent_error, intent),
tpartial(self._display_set_intent_error, intent),
from_other_thread=True,
)
@ -538,10 +564,11 @@ class App:
'Error handling intent %s in app-mode %s.', intent, mode
)
def _apply_intent_error(self, intent: AppIntent) -> None:
def _display_set_intent_error(self, intent: AppIntent) -> None:
"""Show the *user* something went wrong setting an intent."""
from babase._language import Lstr
del intent # Unused.
del intent
_babase.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
_babase.getsimplesound('error').play()
@ -564,19 +591,6 @@ class App:
self._aioloop = _asyncio.setup_asyncio()
self.health_monitor = AppHealthMonitor()
# Only proceed if our config file is healthy so we don't
# overwrite a broken one or whatnot and wipe out data.
if not self.config_file_healthy:
if self.classic is not None:
handled = self.classic.show_config_error_window()
if handled:
return
# For now on other systems we just overwrite the bum config.
# At this point settings are already set; lets just commit
# them to disk.
_appconfig.commit_app_config(force=True)
# __FEATURESET_APP_SUBSYSTEM_CREATE_BEGIN__
# This section generated by batools.appmodule; do not edit.
@ -726,15 +740,15 @@ class App:
_babase.lifecyclelog('app state shutting down')
self._on_shutting_down()
elif self._native_paused:
# Entering paused state:
if self.state is not self.State.PAUSED:
self.state = self.State.PAUSED
self._on_pause()
elif self._native_suspended:
# Entering suspended state:
if self.state is not self.State.SUSPENDED:
self.state = self.State.SUSPENDED
self._on_suspend()
else:
# Leaving paused state:
if self.state is self.State.PAUSED:
self._on_resume()
# Leaving suspended state:
if self.state is self.State.SUSPENDED:
self._on_unsuspend()
# Entering or returning to running state
if self._initial_sign_in_completed and self._meta_scan_completed:
@ -768,7 +782,7 @@ class App:
self.state = self.State.NATIVE_BOOTSTRAPPING
_babase.lifecyclelog('app state native bootstrapping')
else:
# Only logical possibility left is NOT_RUNNING, in which
# Only logical possibility left is NOT_STARTED, in which
# case we should not be getting called.
logging.warning(
'App._update_state called while in %s state;'
@ -780,6 +794,7 @@ class App:
async def _shutdown(self) -> None:
import asyncio
_babase.lock_all_input()
try:
async with asyncio.TaskGroup() as task_group:
for task_coro in self._shutdown_tasks:
@ -809,33 +824,33 @@ class App:
try:
await asyncio.wait_for(task, self.SHUTDOWN_TASK_TIMEOUT_SECONDS)
except Exception:
logging.exception('Error in shutdown task.')
logging.exception('Error in shutdown task (%s).', coro)
def _on_pause(self) -> None:
"""Called when the app goes to a paused state."""
def _on_suspend(self) -> None:
"""Called when the app goes to a suspended state."""
assert _babase.in_logic_thread()
# Pause all app subsystems in the opposite order they were inited.
# Suspend all app subsystems in the opposite order they were inited.
for subsystem in reversed(self._subsystems):
try:
subsystem.on_app_pause()
subsystem.on_app_suspend()
except Exception:
logging.exception(
'Error in on_app_pause for subsystem %s.', subsystem
'Error in on_app_suspend for subsystem %s.', subsystem
)
def _on_resume(self) -> None:
"""Called when resuming."""
def _on_unsuspend(self) -> None:
"""Called when unsuspending."""
assert _babase.in_logic_thread()
self.fg_state += 1
# Resume all app subsystems in the same order they were inited.
# Unsuspend all app subsystems in the same order they were inited.
for subsystem in self._subsystems:
try:
subsystem.on_app_resume()
subsystem.on_app_unsuspend()
except Exception:
logging.exception(
'Error in on_app_resume for subsystem %s.', subsystem
'Error in on_app_unsuspend for subsystem %s.', subsystem
)
def _on_shutting_down(self) -> None:
@ -875,10 +890,45 @@ class App:
import asyncio
# Spin and wait for anything blocking shutdown to complete.
starttime = _babase.apptime()
_babase.lifecyclelog('shutdown-suppress wait begin')
while _babase.shutdown_suppress_count() > 0:
await asyncio.sleep(0.001)
_babase.lifecyclelog('shutdown-suppress wait end')
duration = _babase.apptime() - starttime
if duration > 1.0:
logging.warning(
'Shutdown-suppressions lasted longer than ideal '
'(%.2f seconds).',
duration,
)
async def _fade_and_shutdown_graphics(self) -> None:
import asyncio
# Kick off a short fade and give it time to complete.
_babase.lifecyclelog('fade-and-shutdown-graphics begin')
_babase.fade_screen(False, time=0.15)
await asyncio.sleep(0.15)
# Now tell the graphics system to go down and wait until
# it has done so.
_babase.graphics_shutdown_begin()
while not _babase.graphics_shutdown_is_complete():
await asyncio.sleep(0.01)
_babase.lifecyclelog('fade-and-shutdown-graphics end')
async def _fade_and_shutdown_audio(self) -> None:
import asyncio
# Tell the audio system to go down and give it a bit of
# time to do so gracefully.
_babase.lifecyclelog('fade-and-shutdown-audio begin')
_babase.audio_shutdown_begin()
await asyncio.sleep(0.15)
while not _babase.audio_shutdown_is_complete():
await asyncio.sleep(0.01)
_babase.lifecyclelog('fade-and-shutdown-audio end')
def _threadpool_no_wait_done(self, fut: Future) -> None:
try:
@ -888,243 +938,7 @@ class App:
'Error in work submitted via threadpool_submit_no_wait()'
)
# --------------------------------------------------------------------
# THE FOLLOWING ARE DEPRECATED AND WILL BE REMOVED IN A FUTURE UPDATE.
# --------------------------------------------------------------------
@property
def build_number(self) -> int:
"""Integer build number.
This value increases by at least 1 with each release of the engine.
It is independent of the human readable babase.App.version string.
"""
warnings.warn(
'app.build_number is deprecated; use app.env.build_number',
DeprecationWarning,
stacklevel=2,
)
return self.env.build_number
@property
def device_name(self) -> str:
"""Name of the device running the app."""
warnings.warn(
'app.device_name is deprecated; use app.env.device_name',
DeprecationWarning,
stacklevel=2,
)
return self.env.device_name
@property
def config_file_path(self) -> str:
"""Where the app's config file is stored on disk."""
warnings.warn(
'app.config_file_path is deprecated;'
' use app.env.config_file_path',
DeprecationWarning,
stacklevel=2,
)
return self.env.config_file_path
@property
def version(self) -> str:
"""Human-readable engine version string; something like '1.3.24'.
This should not be interpreted as a number; it may contain
string elements such as 'alpha', 'beta', 'test', etc.
If a numeric version is needed, use `build_number`.
"""
warnings.warn(
'app.version is deprecated; use app.env.version',
DeprecationWarning,
stacklevel=2,
)
return self.env.version
@property
def debug_build(self) -> bool:
"""Whether the app was compiled in debug mode.
Debug builds generally run substantially slower than non-debug
builds due to compiler optimizations being disabled and extra
checks being run.
"""
warnings.warn(
'app.debug_build is deprecated; use app.env.debug',
DeprecationWarning,
stacklevel=2,
)
return self.env.debug
@property
def test_build(self) -> bool:
"""Whether the app was compiled in test mode.
Test mode enables extra checks and features that are useful for
release testing but which do not slow the game down significantly.
"""
warnings.warn(
'app.test_build is deprecated; use app.env.test',
DeprecationWarning,
stacklevel=2,
)
return self.env.test
@property
def data_directory(self) -> str:
"""Path where static app data lives."""
warnings.warn(
'app.data_directory is deprecated; use app.env.data_directory',
DeprecationWarning,
stacklevel=2,
)
return self.env.data_directory
@property
def python_directory_user(self) -> str | None:
"""Path where the app expects its user scripts (mods) to live.
Be aware that this value may be None if ballistica is running in
a non-standard environment, and that python-path modifications may
cause modules to be loaded from other locations.
"""
warnings.warn(
'app.python_directory_user is deprecated;'
' use app.env.python_directory_user',
DeprecationWarning,
stacklevel=2,
)
return self.env.python_directory_user
@property
def python_directory_app(self) -> str | None:
"""Path where the app expects its bundled modules to live.
Be aware that this value may be None if Ballistica is running in
a non-standard environment, and that python-path modifications may
cause modules to be loaded from other locations.
"""
warnings.warn(
'app.python_directory_app is deprecated;'
' use app.env.python_directory_app',
DeprecationWarning,
stacklevel=2,
)
return self.env.python_directory_app
@property
def python_directory_app_site(self) -> str | None:
"""Path where the app expects its bundled pip modules to live.
Be aware that this value may be None if Ballistica is running in
a non-standard environment, and that python-path modifications may
cause modules to be loaded from other locations.
"""
warnings.warn(
'app.python_directory_app_site is deprecated;'
' use app.env.python_directory_app_site',
DeprecationWarning,
stacklevel=2,
)
return self.env.python_directory_app_site
@property
def api_version(self) -> int:
"""The app's api version.
Only Python modules and packages associated with the current API
version number will be detected by the game (see the ba_meta tag).
This value will change whenever substantial backward-incompatible
changes are introduced to ballistica APIs. When that happens,
modules/packages should be updated accordingly and set to target
the newer API version number.
"""
warnings.warn(
'app.api_version is deprecated; use app.env.api_version',
DeprecationWarning,
stacklevel=2,
)
return self.env.api_version
@property
def on_tv(self) -> bool:
"""Whether the app is currently running on a TV."""
warnings.warn(
'app.on_tv is deprecated; use app.env.tv',
DeprecationWarning,
stacklevel=2,
)
return self.env.tv
@property
def vr_mode(self) -> bool:
"""Whether the app is currently running in VR."""
warnings.warn(
'app.vr_mode is deprecated; use app.env.vr',
DeprecationWarning,
stacklevel=2,
)
return self.env.vr
# __SPINOFF_REQUIRE_UI_V1_BEGIN__
@property
def toolbar_test(self) -> bool:
"""(internal)."""
warnings.warn(
'app.toolbar_test is deprecated; use app.ui_v1.use_toolbars',
DeprecationWarning,
stacklevel=2,
)
return self.ui_v1.use_toolbars
# __SPINOFF_REQUIRE_UI_V1_END__
@property
def arcade_mode(self) -> bool:
"""Whether the app is currently running on arcade hardware."""
warnings.warn(
'app.arcade_mode is deprecated; use app.env.arcade',
DeprecationWarning,
stacklevel=2,
)
return self.env.arcade
@property
def headless_mode(self) -> bool:
"""Whether the app is running headlessly."""
warnings.warn(
'app.headless_mode is deprecated; use app.env.headless',
DeprecationWarning,
stacklevel=2,
)
return self.env.headless
@property
def demo_mode(self) -> bool:
"""Whether the app is targeting a demo experience."""
warnings.warn(
'app.demo_mode is deprecated; use app.env.demo',
DeprecationWarning,
stacklevel=2,
)
return self.env.demo
# __SPINOFF_REQUIRE_SCENE_V1_BEGIN__
@property
def protocol_version(self) -> int:
"""(internal)."""
# pylint: disable=cyclic-import
import bascenev1
warnings.warn(
'app.protocol_version is deprecated;'
' use bascenev1.protocol_version()',
DeprecationWarning,
stacklevel=2,
)
return bascenev1.protocol_version()
# __SPINOFF_REQUIRE_SCENE_V1_END__
def _thread_pool_thread_init(self) -> None:
# Help keep things clear in profiling tools/etc.
self._pool_thread_count += 1
_babase.set_thread_name(f'ballistica worker-{self._pool_thread_count}')

View file

@ -101,15 +101,13 @@ class AppConfig(dict):
self.commit()
def read_app_config() -> tuple[AppConfig, bool]:
def read_app_config() -> AppConfig:
"""Read the app config."""
import os
import json
config_file_healthy = False
# NOTE: it is assumed that this only gets called once and the
# config object will not change from here on out
# NOTE: it is assumed that this only gets called once and the config
# object will not change from here on out
config_file_path = _babase.app.env.config_file_path
config_contents = ''
try:
@ -119,20 +117,16 @@ def read_app_config() -> tuple[AppConfig, bool]:
config = AppConfig(json.loads(config_contents))
else:
config = AppConfig()
config_file_healthy = True
except Exception:
logging.exception(
"Error reading config file at time %.3f: '%s'.",
"Error reading config file '%s' at time %.3f.\n"
"Backing up broken config to'%s.broken'.",
config_file_path,
_babase.apptime(),
config_file_path,
)
# Whenever this happens lets back up the broken one just in case it
# gets overwritten accidentally.
logging.info(
"Backing up current config file to '%s.broken'", config_file_path
)
try:
import shutil
@ -141,23 +135,10 @@ def read_app_config() -> tuple[AppConfig, bool]:
logging.exception('Error copying broken config.')
config = AppConfig()
# Now attempt to read one of our 'prev' backup copies.
prev_path = config_file_path + '.prev'
try:
if os.path.exists(prev_path):
with open(prev_path, encoding='utf-8') as infile:
config_contents = infile.read()
config = AppConfig(json.loads(config_contents))
else:
config = AppConfig()
config_file_healthy = True
logging.info('Successfully read backup config.')
except Exception:
logging.exception('Error reading prev backup config.')
return config, config_file_healthy
return config
def commit_app_config(force: bool = False) -> None:
def commit_app_config() -> None:
"""Commit the config to persistent storage.
Category: **General Utility Functions**
@ -167,10 +148,4 @@ def commit_app_config(force: bool = False) -> None:
plus = _babase.app.plus
assert plus is not None
if not _babase.app.config_file_healthy and not force:
logging.warning(
'Current config file is broken; '
'skipping write to avoid losing settings.'
)
return
plus.mark_config_dirty()

View file

@ -31,6 +31,7 @@ class AppMode:
AppExperience associated with the AppMode must be supported by
the current app and runtime environment.
"""
# FIXME: check AppExperience.
return cls._supports_intent(intent)
@classmethod

View file

@ -39,10 +39,10 @@ class AppSubsystem:
def on_app_running(self) -> None:
"""Called when the app reaches the running state."""
def on_app_pause(self) -> None:
def on_app_suspend(self) -> None:
"""Called when the app enters the paused state."""
def on_app_resume(self) -> None:
def on_app_unsuspend(self) -> None:
"""Called when the app exits the paused state."""
def on_app_shutdown(self) -> None:

View file

@ -64,7 +64,9 @@ def get_remote_app_name() -> babase.Lstr:
def should_submit_debug_info() -> bool:
"""(internal)"""
return _babase.app.config.get('Submit Debug Info', True)
val = _babase.app.config.get('Submit Debug Info', True)
assert isinstance(val, bool)
return val
def handle_v1_cloud_log() -> None:
@ -323,7 +325,7 @@ def dump_app_state(
)
def log_dumped_app_state() -> None:
def log_dumped_app_state(from_previous_run: bool = False) -> None:
"""If an app-state dump exists, log it and clear it. No-op otherwise."""
try:
@ -350,8 +352,13 @@ def log_dumped_app_state() -> None:
metadata = dataclass_from_json(DumpedAppStateMetadata, appstatedata)
header = (
'Found app state dump from previous app run'
if from_previous_run
else 'App state dump'
)
out += (
f'App state dump:\nReason: {metadata.reason}\n'
f'{header}:\nReason: {metadata.reason}\n'
f'Time: {metadata.app_time:.2f}'
)
tbpath = os.path.join(
@ -381,9 +388,10 @@ class AppHealthMonitor(AppSubsystem):
def on_app_loading(self) -> None:
# If any traceback dumps happened last run, log and clear them.
log_dumped_app_state()
log_dumped_app_state(from_previous_run=True)
def _app_monitor_thread_main(self) -> None:
_babase.set_thread_name('ballistica app-monitor')
try:
self._monitor_app()
except Exception:
@ -441,10 +449,10 @@ class AppHealthMonitor(AppSubsystem):
self._first_check = False
def on_app_pause(self) -> None:
def on_app_suspend(self) -> None:
assert _babase.in_logic_thread()
self._running = False
def on_app_resume(self) -> None:
def on_app_unsuspend(self) -> None:
assert _babase.in_logic_thread()
self._running = True

View file

@ -26,6 +26,11 @@ DEBUG_LOG = False
class CloudSubsystem(AppSubsystem):
"""Manages communication with cloud components."""
@property
def connected(self) -> bool:
"""Property equivalent of CloudSubsystem.is_connected()."""
return self.is_connected()
def is_connected(self) -> bool:
"""Return whether a connection to the cloud is present.

View file

@ -0,0 +1,188 @@
# Released under the MIT License. See LICENSE for details.
#
"""Dev-Console functionality."""
from __future__ import annotations
import os
from typing import TYPE_CHECKING
from dataclasses import dataclass
import logging
import _babase
if TYPE_CHECKING:
from typing import Callable, Any, Literal
class DevConsoleTab:
"""Defines behavior for a tab in the dev-console."""
def refresh(self) -> None:
"""Called when the tab should refresh itself."""
def request_refresh(self) -> None:
"""The tab can call this to request that it be refreshed."""
_babase.dev_console_request_refresh()
def button(
self,
label: str,
pos: tuple[float, float],
size: tuple[float, float],
call: Callable[[], Any] | None = None,
h_anchor: Literal['left', 'center', 'right'] = 'center',
label_scale: float = 1.0,
corner_radius: float = 8.0,
style: Literal['normal', 'dark'] = 'normal',
) -> None:
"""Add a button to the tab being refreshed."""
assert _babase.app.devconsole.is_refreshing
_babase.dev_console_add_button(
label,
pos[0],
pos[1],
size[0],
size[1],
call,
h_anchor,
label_scale,
corner_radius,
style,
)
def text(
self,
text: str,
pos: tuple[float, float],
h_anchor: Literal['left', 'center', 'right'] = 'center',
h_align: Literal['left', 'center', 'right'] = 'center',
v_align: Literal['top', 'center', 'bottom', 'none'] = 'center',
scale: float = 1.0,
) -> None:
"""Add a button to the tab being refreshed."""
assert _babase.app.devconsole.is_refreshing
_babase.dev_console_add_text(
text, pos[0], pos[1], h_anchor, h_align, v_align, scale
)
def python_terminal(self) -> None:
"""Add a Python Terminal to the tab being refreshed."""
assert _babase.app.devconsole.is_refreshing
_babase.dev_console_add_python_terminal()
@property
def width(self) -> float:
"""Return the current tab width. Only call during refreshes."""
assert _babase.app.devconsole.is_refreshing
return _babase.dev_console_tab_width()
@property
def height(self) -> float:
"""Return the current tab height. Only call during refreshes."""
assert _babase.app.devconsole.is_refreshing
return _babase.dev_console_tab_height()
@property
def base_scale(self) -> float:
"""A scale value set depending on the app's UI scale.
Dev-console tabs can incorporate this into their UI sizes and
positions if they desire. This must be done manually however.
"""
assert _babase.app.devconsole.is_refreshing
return _babase.dev_console_base_scale()
class DevConsoleTabPython(DevConsoleTab):
"""The Python dev-console tab."""
def refresh(self) -> None:
self.python_terminal()
class DevConsoleTabTest(DevConsoleTab):
"""Test dev-console tab."""
def refresh(self) -> None:
import random
self.button(
f'FLOOP-{random.randrange(200)}',
pos=(10, 10),
size=(100, 30),
h_anchor='left',
label_scale=0.6,
call=self.request_refresh,
)
self.button(
f'FLOOP2-{random.randrange(200)}',
pos=(120, 10),
size=(100, 30),
h_anchor='left',
label_scale=0.6,
style='dark',
)
self.text(
'TestText',
scale=0.8,
pos=(15, 50),
h_anchor='left',
h_align='left',
v_align='none',
)
@dataclass
class DevConsoleTabEntry:
"""Represents a distinct tab in the dev-console."""
name: str
factory: Callable[[], DevConsoleTab]
class DevConsoleSubsystem:
"""Subsystem for wrangling the dev console.
The single instance of this class can be found at
babase.app.devconsole. The dev-console is a simple always-available
UI intended for use by developers; not end users. Traditionally it
is available by typing a backtick (`) key on a keyboard, but now can
be accessed via an on-screen button (see settings/advanced to enable
said button).
"""
def __init__(self) -> None:
# All tabs in the dev-console. Add your own stuff here via
# plugins or whatnot.
self.tabs: list[DevConsoleTabEntry] = [
DevConsoleTabEntry('Python', DevConsoleTabPython)
]
if os.environ.get('BA_DEV_CONSOLE_TEST_TAB', '0') == '1':
self.tabs.append(DevConsoleTabEntry('Test', DevConsoleTabTest))
self.is_refreshing = False
def do_refresh_tab(self, tabname: str) -> None:
"""Called by the C++ layer when a tab should be filled out."""
assert _babase.in_logic_thread()
# FIXME: We currently won't handle multiple tabs with the same
# name. We should give a clean error or something in that case.
tab: DevConsoleTab | None = None
for tabentry in self.tabs:
if tabentry.name == tabname:
tab = tabentry.factory()
break
if tab is None:
logging.error(
'DevConsole got refresh request for tab'
" '%s' which does not exist.",
tabname,
)
return
self.is_refreshing = True
try:
tab.refresh()
finally:
self.is_refreshing = False

View file

@ -40,6 +40,11 @@ def on_native_module_import() -> None:
if envconfig.log_handler is not None:
_feed_logs_to_babase(envconfig.log_handler)
# Also let's name the log-handler thread to help in profiling.
envconfig.log_handler.call_in_thread(
lambda: _babase.set_thread_name('ballistica logging')
)
env = _babase.pre_env()
# Give a soft warning if we're being used with a different binary
@ -180,10 +185,8 @@ def _feed_logs_to_babase(log_handler: LogHandler) -> None:
def _on_log(entry: LogEntry) -> None:
# Forward this along to the engine to display in the in-app
# console, in the Android log, etc.
_babase.display_log(
name=entry.name,
level=entry.level.name,
message=entry.message,
_babase.emit_log(
name=entry.name, level=entry.level.name, message=entry.message
)
# We also want to feed some logs to the old v1-cloud-log system.

View file

@ -33,18 +33,47 @@ def reset_to_main_menu() -> None:
logging.warning('reset_to_main_menu: no-op due to classic not present.')
def set_config_fullscreen_on() -> None:
def get_v2_account_id() -> str | None:
"""Return the current V2 account id if signed in, or None if not."""
try:
plus = _babase.app.plus
if plus is not None:
account = plus.accounts.primary
if account is not None:
accountid = account.accountid
# (Avoids mypy complaints when plus is not present)
assert isinstance(accountid, (str, type(None)))
return accountid
return None
except Exception:
logging.exception('Error fetching v2 account id.')
return None
def store_config_fullscreen_on() -> None:
"""The OS has changed our fullscreen state and we should take note."""
_babase.app.config['Fullscreen'] = True
_babase.app.config.commit()
def set_config_fullscreen_off() -> None:
def store_config_fullscreen_off() -> None:
"""The OS has changed our fullscreen state and we should take note."""
_babase.app.config['Fullscreen'] = False
_babase.app.config.commit()
def set_config_fullscreen_on() -> None:
"""Set and store fullscreen state"""
_babase.app.config['Fullscreen'] = True
_babase.app.config.apply_and_commit()
def set_config_fullscreen_off() -> None:
"""The OS has changed our fullscreen state and we should take note."""
_babase.app.config['Fullscreen'] = False
_babase.app.config.apply_and_commit()
def not_signed_in_screen_message() -> None:
from babase._language import Lstr
@ -111,6 +140,14 @@ def error_message() -> None:
_babase.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
def success_message() -> None:
from babase._language import Lstr
if _babase.app.env.gui:
_babase.getsimplesound('dingSmall').play()
_babase.screenmessage(Lstr(resource='successText'), color=(0, 1, 0))
def purchase_not_valid_error() -> None:
from babase._language import Lstr
@ -300,6 +337,7 @@ def implicit_sign_in(
from bacommon.login import LoginType
assert _babase.app.plus is not None
_babase.app.plus.accounts.on_implicit_sign_in(
login_type=LoginType(login_type_str),
login_id=login_id,
@ -372,3 +410,22 @@ def string_edit_adapter_can_be_replaced(adapter: StringEditAdapter) -> bool:
assert isinstance(adapter, StringEditAdapter)
return adapter.can_be_replaced()
def get_dev_console_tab_names() -> list[str]:
"""Return the current set of dev-console tab names."""
return [t.name for t in _babase.app.devconsole.tabs]
def unsupported_controller_message(name: str) -> None:
"""Print a message when an unsupported controller is connected."""
from babase._language import Lstr
# Ick; this can get called early in the bootstrapping process
# before we're allowed to load assets. Guard against that.
if _babase.asset_loads_allowed():
_babase.getsimplesound('error').play()
_babase.screenmessage(
Lstr(resource='unsupportedControllerText', subs=[('${NAME}', name)]),
color=(1, 0, 0),
)

View file

@ -20,6 +20,13 @@ if TYPE_CHECKING:
DEBUG_LOG = False
@dataclass
class LoginInfo:
"""Basic info about a login available in the app.plus.accounts section."""
name: str
class LoginAdapter:
"""Allows using implicit login types in an explicit way.
@ -138,7 +145,7 @@ class LoginAdapter:
is actually being used by the app. It should therefore register
unlocked achievements, leaderboard scores, allow viewing native
UIs, etc. When not active it should ignore everything and behave
as if logged out, even if it technically is still logged in.
as if signed out, even if it technically is still signed in.
"""
assert _babase.in_logic_thread()
del active # Unused.
@ -149,7 +156,7 @@ class LoginAdapter:
result_cb: Callable[[LoginAdapter, SignInResult | Exception], None],
description: str,
) -> None:
"""Attempt an explicit sign in via this adapter.
"""Attempt to sign in via this adapter.
This can be called even if the back-end is not implicitly signed in;
the adapter will attempt to sign in if possible. An exception will
@ -161,7 +168,7 @@ class LoginAdapter:
# Have been seeing multiple sign-in attempts come through
# nearly simultaneously which can be problematic server-side.
# Let's error if a sign-in attempt is made within a few seconds
# of the last one to address this.
# of the last one to try and address this.
now = time.monotonic()
appnow = _babase.apptime()
if self._last_sign_in_time is not None:
@ -229,6 +236,7 @@ class LoginAdapter:
def _got_sign_in_response(
response: bacommon.cloud.SignInResponse | Exception,
) -> None:
# This likely means we couldn't communicate with the server.
if isinstance(response, Exception):
if DEBUG_LOG:
logging.debug(
@ -238,6 +246,12 @@ class LoginAdapter:
response,
)
_babase.pushcall(Call(result_cb, self, response))
else:
# This means our credentials were explicitly rejected.
if response.credentials is None:
result2: LoginAdapter.SignInResult | Exception = (
RuntimeError('Sign-in-token was rejected.')
)
else:
if DEBUG_LOG:
logging.debug(
@ -245,14 +259,6 @@ class LoginAdapter:
' sign-in response',
self.login_type.name,
)
if response.credentials is None:
result2: LoginAdapter.SignInResult | Exception = (
RuntimeError(
'No credentials returned after'
' submitting sign-in-token.'
)
)
else:
result2 = self.SignInResult(
credentials=response.credentials
)
@ -269,7 +275,7 @@ class LoginAdapter:
on_response=_got_sign_in_response,
)
# Kick off the process by fetching a sign-in token.
# Kick off the sign-in process by fetching a sign-in token.
self.get_sign_in_token(completion_cb=_got_sign_in_token_result)
def is_back_end_active(self) -> bool:
@ -282,11 +288,10 @@ class LoginAdapter:
"""Get a sign-in token from the adapter back end.
This token is then passed to the master-server to complete the
login process.
The adapter can use this opportunity to bring up account creation
UI, call its internal sign_in function, etc. as needed.
The provided completion_cb should then be called with either a token
or None if sign in failed or was cancelled.
sign-in process. The adapter can use this opportunity to bring
up account creation UI, call its internal sign_in function, etc.
as needed. The provided completion_cb should then be called with
either a token or None if sign in failed or was cancelled.
"""
from babase._general import Call
@ -295,7 +300,7 @@ class LoginAdapter:
def _update_implicit_login_state(self) -> None:
# If we've received an implicit login state, schedule it to be
# sent along to the app. We wait until on-app-launch has been
# sent along to the app. We wait until on-app-loading has been
# called so that account-client-v2 has had a chance to load
# any existing state so it can properly respond to this.
if self._implicit_login_state_dirty and self._on_app_loading_called:
@ -340,8 +345,8 @@ class LoginAdapter:
class LoginAdapterNative(LoginAdapter):
"""A login adapter that does its work in the native layer."""
def __init__(self) -> None:
super().__init__(LoginType.GPGS)
def __init__(self, login_type: LoginType) -> None:
super().__init__(login_type)
# Store int ids for in-flight attempts since they may go through
# various platform layers and back.
@ -375,3 +380,13 @@ class LoginAdapterNative(LoginAdapter):
class LoginAdapterGPGS(LoginAdapterNative):
"""Google Play Game Services adapter."""
def __init__(self) -> None:
super().__init__(LoginType.GPGS)
class LoginAdapterGameCenter(LoginAdapterNative):
"""Apple Game Center adapter."""
def __init__(self) -> None:
super().__init__(LoginType.GAME_CENTER)

View file

@ -24,6 +24,8 @@ if TYPE_CHECKING:
# instead of these or to make the meta system aware of arbitrary classes.
EXPORT_CLASS_NAME_SHORTCUTS: dict[str, str] = {
'plugin': 'babase.Plugin',
# DEPRECATED as of 12/2023. Currently am warning if finding these
# but should take this out eventually.
'keyboard': 'babase.Keyboard',
}
@ -414,25 +416,22 @@ class DirectoryScan:
if export_class_name is not None:
classname = modulename + '.' + export_class_name
# Since we'll soon have multiple versions of 'game'
# classes we need to migrate people to using base
# class names for them.
if exporttypestr == 'game':
# Migrating away from the 'keyboard' name shortcut
# since it's specific to bauiv1; warn if we find it.
if exporttypestr == 'keyboard':
logging.warning(
"metascan: %s:%d: '# ba_meta export"
" game' tag should be replaced by '# ba_meta"
" export bascenev1.GameActivity'.",
" keyboard' tag should be replaced by '# ba_meta"
" export bauiv1.Keyboard'.",
subpath,
lindex + 1,
)
self.results.announce_errors_occurred = True
else:
# If export type is one of our shortcuts, sub in the
# actual class path. Otherwise assume its a classpath
# itself.
exporttype = EXPORT_CLASS_NAME_SHORTCUTS.get(
exporttypestr
)
exporttype = EXPORT_CLASS_NAME_SHORTCUTS.get(exporttypestr)
if exporttype is None:
exporttype = exporttypestr
self.results.exports.setdefault(exporttype, []).append(

View file

@ -38,6 +38,27 @@ class InputType(Enum):
DOWN_RELEASE = 26
class QuitType(Enum):
"""Types of input a controller can send to the game.
Category: Enums
'soft' may hide/reset the app but keep the process running, depending
on the platform.
'back' is a variant of 'soft' which may give 'back-button-pressed'
behavior depending on the platform. (returning to some previous
activity instead of dumping to the home screen, etc.)
'hard' leads to the process exiting. This generally should be avoided
on platforms such as mobile.
"""
SOFT = 0
BACK = 1
HARD = 2
class UIScale(Enum):
"""The overall scale the UI is being rendered for. Note that this is
independent of pixel resolution. For example, a phone and a desktop PC

View file

@ -170,23 +170,23 @@ class PluginSubsystem(AppSubsystem):
_error.print_exception('Error in plugin on_app_running()')
def on_app_pause(self) -> None:
def on_app_suspend(self) -> None:
for plugin in self.active_plugins:
try:
plugin.on_app_pause()
plugin.on_app_suspend()
except Exception:
from babase import _error
_error.print_exception('Error in plugin on_app_pause()')
_error.print_exception('Error in plugin on_app_suspend()')
def on_app_resume(self) -> None:
def on_app_unsuspend(self) -> None:
for plugin in self.active_plugins:
try:
plugin.on_app_resume()
plugin.on_app_unsuspend()
except Exception:
from babase import _error
_error.print_exception('Error in plugin on_app_resume()')
_error.print_exception('Error in plugin on_app_unsuspend()')
def on_app_shutdown(self) -> None:
for plugin in self.active_plugins:
@ -327,11 +327,11 @@ class Plugin:
def on_app_running(self) -> None:
"""Called when the app reaches the running state."""
def on_app_pause(self) -> None:
"""Called when the app is switching to a paused state."""
def on_app_suspend(self) -> None:
"""Called when the app enters the suspended state."""
def on_app_resume(self) -> None:
"""Called when the app is resuming from a paused state."""
def on_app_unsuspend(self) -> None:
"""Called when the app exits the suspended state."""
def on_app_shutdown(self) -> None:
"""Called when the app is beginning the shutdown process."""

View file

@ -104,8 +104,8 @@ def show_user_scripts() -> None:
_error.print_exception('error writing about_this_folder stuff')
# On a few platforms we try to open the dir in the UI.
if app.classic is not None and app.classic.platform in ['mac', 'windows']:
# On platforms that support it, open the dir in the UI.
if _babase.supports_open_dir_externally():
_babase.open_dir_externally(env.python_directory_user)
# Otherwise we just print a pretty version of it.

View file

@ -49,10 +49,10 @@ class AccountV1Subsystem:
babase.pushcall(do_auto_sign_in)
def on_app_pause(self) -> None:
def on_app_suspend(self) -> None:
"""Should be called when app is pausing."""
def on_app_resume(self) -> None:
def on_app_unsuspend(self) -> None:
"""Should be called when the app is resumed."""
# Mark our cached tourneys as invalid so anyone using them knows
@ -302,6 +302,11 @@ class AccountV1Subsystem:
"""(internal)"""
plus = babase.app.plus
if plus is None:
import logging
logging.warning(
'Error adding pending promo code; plus not present.'
)
babase.screenmessage(
babase.Lstr(resource='errorText'), color=(1, 0, 0)
)

View file

@ -4,10 +4,11 @@
from __future__ import annotations
import time
import asyncio
import logging
from typing import TYPE_CHECKING
import babase
import bauiv1
import bascenev1
if TYPE_CHECKING:
@ -31,6 +32,7 @@ class AdsSubsystem:
self.last_in_game_ad_remove_message_show_time: float | None = None
self.last_ad_completion_time: float | None = None
self.last_ad_was_short = False
self._fallback_task: asyncio.Task | None = None
def do_remove_in_game_ads_message(self) -> None:
"""(internal)"""
@ -69,7 +71,8 @@ class AdsSubsystem:
) -> None:
"""(internal)"""
self.last_ad_purpose = purpose
bauiv1.show_ad(purpose, on_completion_call)
assert babase.app.plus is not None
babase.app.plus.show_ad(purpose, on_completion_call)
def show_ad_2(
self,
@ -78,7 +81,8 @@ class AdsSubsystem:
) -> None:
"""(internal)"""
self.last_ad_purpose = purpose
bauiv1.show_ad_2(purpose, on_completion_call)
assert babase.app.plus is not None
babase.app.plus.show_ad_2(purpose, on_completion_call)
def call_after_ad(self, call: Callable[[], Any]) -> None:
"""Run a call after potentially showing an ad."""
@ -94,7 +98,7 @@ class AdsSubsystem:
show = True
# No ads without net-connections, etc.
if not bauiv1.can_show_ad():
if not plus.can_show_ad():
show = False
if classic.accounts.have_pro():
show = False # Pro disables interstitials.
@ -132,7 +136,7 @@ class AdsSubsystem:
# ad-show-threshold and see if we should *actually* show
# (we reach our threshold faster the longer we've been
# playing).
base = 'ads' if bauiv1.has_video_ads() else 'ads2'
base = 'ads' if plus.has_video_ads() else 'ads2'
min_lc = plus.get_v1_account_misc_read_val(base + '.minLC', 0.0)
max_lc = plus.get_v1_account_misc_read_val(base + '.maxLC', 5.0)
min_lc_scale = plus.get_v1_account_misc_read_val(
@ -181,36 +185,53 @@ class AdsSubsystem:
# If we're *still* cleared to show, actually tell the system to show.
if show:
# As a safety-check, set up an object that will run
# the completion callback if we've returned and sat for 10 seconds
# (in case some random ad network doesn't properly deliver its
# completion callback).
# As a safety-check, we set up an object that will run the
# completion callback if we've returned and sat for several
# seconds (in case some random ad network doesn't properly
# deliver its completion callback).
class _Payload:
def __init__(self, pcall: Callable[[], Any]):
self._call = pcall
self._ran = False
def run(self, fallback: bool = False) -> None:
"""Run fallback call (and issue a warning about it)."""
"""Run the payload."""
assert app.classic is not None
if not self._ran:
if fallback:
lanst = app.classic.ads.last_ad_network_set_time
print(
'ERROR: relying on fallback ad-callback! '
'last network: '
+ app.classic.ads.last_ad_network
+ ' (set '
+ str(int(time.time() - lanst))
+ 's ago); purpose='
+ app.classic.ads.last_ad_purpose
logging.error(
'Relying on fallback ad-callback! '
'last network: %s (set %s seconds ago);'
' purpose=%s.',
app.classic.ads.last_ad_network,
time.time() - lanst,
app.classic.ads.last_ad_purpose,
)
babase.pushcall(self._call)
self._ran = True
payload = _Payload(call)
# Set up our backup.
with babase.ContextRef.empty():
babase.apptimer(5.0, lambda: payload.run(fallback=True))
# Note to self: Previously this was a simple 5 second
# timer because the app got totally suspended while ads
# were showing (which delayed the timer), but these days
# the app may continue to run, so we need to be more
# careful and only fire the fallback after we see that
# the app has been front-and-center for several seconds.
async def add_fallback_task() -> None:
activesecs = 5
while activesecs > 0:
if babase.app.active:
activesecs -= 1
await asyncio.sleep(1.0)
payload.run(fallback=True)
_fallback_task = babase.app.aioloop.create_task(
add_fallback_task()
)
self.show_ad('between_game', on_completion_call=payload.run)
else:
babase.pushcall(call) # Just run the callback without the ad.

View file

@ -41,5 +41,6 @@ class AppDelegate:
sessiontype,
settings,
completion_call=completion_call,
).get_root_widget()
).get_root_widget(),
from_window=False, # Disable check since we don't know.
)

View file

@ -8,6 +8,7 @@ from typing import TYPE_CHECKING
import babase
import bascenev1
import _baclassic
if TYPE_CHECKING:
from typing import Any, Sequence
@ -54,7 +55,6 @@ def run_stress_test(
round_duration: int = 30,
) -> None:
"""Run a stress test."""
from babase import modutils
babase.screenmessage(
"Beginning stress test.. use 'End Test' to stop testing.",
@ -69,22 +69,12 @@ def run_stress_test(
'round_duration': round_duration,
}
)
babase.apptimer(
7.0,
babase.Call(
babase.screenmessage,
(
'stats will be written to '
+ modutils.get_human_readable_user_scripts_path()
+ '/stress_test_stats.csv'
),
),
)
def stop_stress_test() -> None:
"""End a running stress test."""
babase.set_stress_testing(False, 0)
_baclassic.set_stress_testing(False, 0)
assert babase.app.classic is not None
try:
if babase.app.classic.stress_test_reset_timer is not None:
@ -134,14 +124,14 @@ def start_stress_test(args: dict[str, Any]) -> None:
babase.Call(bascenev1.new_host_session, FreeForAllSession),
),
)
babase.set_stress_testing(True, args['player_count'])
_baclassic.set_stress_testing(True, args['player_count'])
babase.app.classic.stress_test_reset_timer = babase.AppTimer(
args['round_duration'], babase.Call(_reset_stress_test, args)
)
def _reset_stress_test(args: dict[str, Any]) -> None:
babase.set_stress_testing(False, args['player_count'])
_baclassic.set_stress_testing(False, args['player_count'])
babase.screenmessage('Resetting stress test...')
session = bascenev1.get_foreground_host_session()
assert session is not None

View file

@ -20,7 +20,6 @@ def get_input_device_mapped_value(
This checks the user config and falls back to default values
where available.
"""
# pylint: disable=too-many-statements
# pylint: disable=too-many-return-statements
# pylint: disable=too-many-branches
@ -40,7 +39,14 @@ def get_input_device_mapped_value(
mapping = ccfgs[devicename][unique_id]
elif 'default' in ccfgs[devicename]:
mapping = ccfgs[devicename]['default']
if mapping is not None:
# We now use the config mapping *only* if it is not empty.
# There have been cases of config writing code messing up
# and leaving empty dicts in the app config, which currently
# leaves the device unusable. Alternatively, we'd perhaps
# want to fall back to defaults for individual missing
# values, but that is a bigger change we can make later.
if isinstance(mapping, dict) and mapping:
return mapping.get(name, -1)
if platform == 'windows':
@ -76,91 +82,6 @@ def get_input_device_mapped_value(
'triggerRun1': 5,
}.get(name, -1)
# Look for some exact types.
if babase.is_running_on_fire_tv():
if devicename in ['Thunder', 'Amazon Fire Game Controller']:
return {
'triggerRun2': 23,
'unassignedButtonsRun': False,
'buttonPickUp': 101,
'buttonBomb': 98,
'buttonJump': 97,
'analogStickDeadZone': 0.0,
'startButtonActivatesDefaultWidget': False,
'buttonStart': 83,
'buttonPunch': 100,
'buttonRun2': 103,
'buttonRun1': 104,
'triggerRun1': 24,
}.get(name, -1)
if devicename == 'NYKO PLAYPAD PRO':
return {
'triggerRun2': 23,
'triggerRun1': 24,
'buttonPickUp': 101,
'buttonBomb': 98,
'buttonJump': 97,
'buttonUp': 20,
'buttonLeft': 22,
'buttonRight': 23,
'buttonStart': 83,
'buttonPunch': 100,
'buttonDown': 21,
}.get(name, -1)
if devicename == 'Logitech Dual Action':
return {
'triggerRun2': 23,
'triggerRun1': 24,
'buttonPickUp': 98,
'buttonBomb': 101,
'buttonJump': 100,
'buttonStart': 109,
'buttonPunch': 97,
}.get(name, -1)
if devicename == 'Xbox 360 Wireless Receiver':
return {
'triggerRun2': 23,
'triggerRun1': 24,
'buttonPickUp': 101,
'buttonBomb': 98,
'buttonJump': 97,
'buttonUp': 20,
'buttonLeft': 22,
'buttonRight': 23,
'buttonStart': 83,
'buttonPunch': 100,
'buttonDown': 21,
}.get(name, -1)
if devicename == 'Microsoft X-Box 360 pad':
return {
'triggerRun2': 23,
'triggerRun1': 24,
'buttonPickUp': 101,
'buttonBomb': 98,
'buttonJump': 97,
'buttonStart': 83,
'buttonPunch': 100,
}.get(name, -1)
if devicename in [
'Amazon Remote',
'Amazon Bluetooth Dev',
'Amazon Fire TV Remote',
]:
return {
'triggerRun2': 23,
'triggerRun1': 24,
'buttonPickUp': 24,
'buttonBomb': 91,
'buttonJump': 86,
'buttonUp': 20,
'buttonLeft': 22,
'startButtonActivatesDefaultWidget': False,
'buttonRight': 23,
'buttonStart': 83,
'buttonPunch': 90,
'buttonDown': 21,
}.get(name, -1)
elif 'NVIDIA SHIELD;' in useragentstring:
if 'NVIDIA Controller' in devicename:
return {
@ -175,112 +96,6 @@ def get_input_device_mapped_value(
'buttonIgnored': 184,
'buttonIgnored2': 86,
}.get(name, -1)
elif platform == 'mac':
if devicename == 'PLAYSTATION(R)3 Controller':
return {
'buttonLeft': 8,
'buttonUp': 5,
'buttonRight': 6,
'buttonDown': 7,
'buttonJump': 15,
'buttonPunch': 16,
'buttonBomb': 14,
'buttonPickUp': 13,
'buttonStart': 4,
'buttonIgnored': 17,
}.get(name, -1)
if devicename in ['Wireless 360 Controller', 'Controller']:
# Xbox360 gamepads
return {
'analogStickDeadZone': 1.2,
'buttonBomb': 13,
'buttonDown': 2,
'buttonJump': 12,
'buttonLeft': 3,
'buttonPickUp': 15,
'buttonPunch': 14,
'buttonRight': 4,
'buttonStart': 5,
'buttonUp': 1,
'triggerRun1': 5,
'triggerRun2': 6,
'buttonIgnored': 11,
}.get(name, -1)
if devicename in [
'Logitech Dual Action',
'Logitech Cordless RumblePad 2',
]:
return {
'buttonJump': 2,
'buttonPunch': 1,
'buttonBomb': 3,
'buttonPickUp': 4,
'buttonStart': 10,
}.get(name, -1)
# Old gravis gamepad.
if devicename == 'GamePad Pro USB ':
return {
'buttonJump': 2,
'buttonPunch': 1,
'buttonBomb': 3,
'buttonPickUp': 4,
'buttonStart': 10,
}.get(name, -1)
if devicename == 'Microsoft SideWinder Plug & Play Game Pad':
return {
'buttonJump': 1,
'buttonPunch': 3,
'buttonBomb': 2,
'buttonPickUp': 4,
'buttonStart': 6,
}.get(name, -1)
# Saitek P2500 Rumble Force Pad.. (hopefully works for others too?..)
if devicename == 'Saitek P2500 Rumble Force Pad':
return {
'buttonJump': 3,
'buttonPunch': 1,
'buttonBomb': 4,
'buttonPickUp': 2,
'buttonStart': 11,
}.get(name, -1)
# Some crazy 'Senze' dual gamepad.
if devicename == 'Twin USB Joystick':
return {
'analogStickLR': 3,
'analogStickLR_B': 7,
'analogStickUD': 4,
'analogStickUD_B': 8,
'buttonBomb': 2,
'buttonBomb_B': 14,
'buttonJump': 3,
'buttonJump_B': 15,
'buttonPickUp': 1,
'buttonPickUp_B': 13,
'buttonPunch': 4,
'buttonPunch_B': 16,
'buttonRun1': 7,
'buttonRun1_B': 19,
'buttonRun2': 8,
'buttonRun2_B': 20,
'buttonStart': 10,
'buttonStart_B': 22,
'enableSecondary': 1,
'unassignedButtonsRun': False,
}.get(name, -1)
if devicename == 'USB Gamepad ': # some weird 'JITE' gamepad
return {
'analogStickLR': 4,
'analogStickUD': 5,
'buttonJump': 3,
'buttonPunch': 4,
'buttonBomb': 2,
'buttonPickUp': 1,
'buttonStart': 10,
}.get(name, -1)
default_android_mapping = {
'triggerRun2': 19,
@ -303,6 +118,41 @@ def get_input_device_mapped_value(
# Generic android...
if platform == 'android':
if devicename in ['Amazon Fire Game Controller']:
return {
'triggerRun2': 23,
'unassignedButtonsRun': False,
'buttonPickUp': 101,
'buttonBomb': 98,
'buttonJump': 97,
'analogStickDeadZone': 0.0,
'startButtonActivatesDefaultWidget': False,
'buttonStart': 83,
'buttonPunch': 100,
'buttonRun2': 103,
'buttonRun1': 104,
'triggerRun1': 24,
}.get(name, -1)
if devicename in [
'Amazon Remote',
'Amazon Bluetooth Dev',
'Amazon Fire TV Remote',
]:
return {
'triggerRun2': 23,
'triggerRun1': 24,
'buttonPickUp': 24,
'buttonBomb': 91,
'buttonJump': 86,
'buttonUp': 20,
'buttonLeft': 22,
'startButtonActivatesDefaultWidget': False,
'buttonRight': 23,
'buttonStart': 83,
'buttonPunch': 90,
'buttonDown': 21,
}.get(name, -1)
# Steelseries stratus xl.
if devicename == 'SteelSeries Stratus XL':
return {
@ -380,14 +230,6 @@ def get_input_device_mapped_value(
'uiOnly': True,
}.get(name, -1)
# flag particular gamepads to use exact android defaults..
# (so they don't even ask to configure themselves)
if devicename in [
'Samsung Game Pad EI-GP20',
'ASUS Gamepad',
] or devicename.startswith('Freefly VR Glide'):
return default_android_mapping.get(name, -1)
# Nvidia controller is default, but gets some strange
# keypresses we want to ignore.. touching the touchpad,
# so lets ignore those.
@ -445,76 +287,11 @@ def get_input_device_mapped_value(
'buttonRight': 100,
}.get(name, -1)
# Ok, this gamepad's not in our specific preset list;
# fall back to some (hopefully) reasonable defaults.
# Leaving these in here for now but not gonna add any more now that we have
# fancy-pants config sharing across the internet.
if platform == 'mac':
if 'PLAYSTATION' in devicename: # ps3 gamepad?..
return {
'buttonLeft': 8,
'buttonUp': 5,
'buttonRight': 6,
'buttonDown': 7,
'buttonJump': 15,
'buttonPunch': 16,
'buttonBomb': 14,
'buttonPickUp': 13,
'buttonStart': 4,
}.get(name, -1)
# Dual Action Config - hopefully applies to more...
if 'Logitech' in devicename:
return {
'buttonJump': 2,
'buttonPunch': 1,
'buttonBomb': 3,
'buttonPickUp': 4,
'buttonStart': 10,
}.get(name, -1)
# Saitek P2500 Rumble Force Pad.. (hopefully works for others too?..)
if 'Saitek' in devicename:
return {
'buttonJump': 3,
'buttonPunch': 1,
'buttonBomb': 4,
'buttonPickUp': 2,
'buttonStart': 11,
}.get(name, -1)
# Gravis stuff?...
if 'GamePad' in devicename:
return {
'buttonJump': 2,
'buttonPunch': 1,
'buttonBomb': 3,
'buttonPickUp': 4,
'buttonStart': 10,
}.get(name, -1)
# Ok, this gamepad's not in our specific preset list; fall back to
# some (hopefully) reasonable defaults.
# Reasonable defaults.
if platform == 'android':
if babase.is_running_on_fire_tv():
# Mostly same as default firetv controller.
return {
'triggerRun2': 23,
'triggerRun1': 24,
'buttonPickUp': 101,
'buttonBomb': 98,
'buttonJump': 97,
'buttonStart': 83,
'buttonPunch': 100,
'buttonDown': 21,
'buttonUp': 20,
'buttonLeft': 22,
'buttonRight': 23,
'startButtonActivatesDefaultWidget': False,
}.get(name, -1)
# Mostly same as 'Gamepad' except with 'menu' for default start
# button instead of 'mode'.
return default_android_mapping.get(name, -1)
# Is there a point to any sort of fallbacks here?.. should check.
@ -533,9 +310,9 @@ def _gen_android_input_hash() -> str:
md5 = hashlib.md5()
# Currently we just do a single hash of *all* inputs on android
# and that's it.. good enough.
# (grabbing mappings for a specific device looks to be non-trivial)
# Currently we just do a single hash of *all* inputs on android and
# that's it. Good enough. (grabbing mappings for a specific device
# looks to be non-trivial)
for dirname in [
'/system/usr/keylayout',
'/data/usr/keylayout',
@ -544,9 +321,9 @@ def _gen_android_input_hash() -> str:
try:
if os.path.isdir(dirname):
for f_name in os.listdir(dirname):
# This is usually volume keys and stuff;
# assume we can skip it?..
# (since it'll vary a lot across devices)
# This is usually volume keys and stuff; assume we
# can skip it?.. (since it'll vary a lot across
# devices)
if f_name == 'gpio-keys.kl':
continue
try:
@ -569,8 +346,8 @@ def get_input_device_map_hash() -> str:
"""
app = babase.app
# Currently only using this when classic is present.
# Need to replace with a modern equivalent.
# Currently only using this when classic is present. Need to replace
# with a modern equivalent.
if app.classic is not None:
try:
if app.classic.input_map_hash is None:

View file

@ -165,15 +165,16 @@ class MusicSubsystem:
def supports_soundtrack_entry_type(self, entry_type: str) -> bool:
"""Return whether provided soundtrack entry type is supported here."""
uas = babase.env()['legacy_user_agent_string']
assert isinstance(uas, str)
# FIXME: Generalize this.
# Note to self; can't access babase.app.classic here because
# we are called during its construction.
env = babase.env()
platform = env.get('platform')
assert isinstance(platform, str)
if entry_type == 'iTunesPlaylist':
return 'Mac' in uas
return platform == 'mac' and babase.is_xcode_build()
if entry_type in ('musicFile', 'musicFolder'):
return (
'android' in uas
platform == 'android'
and babase.android_get_external_files_dir() is not None
)
if entry_type == 'default':
@ -239,7 +240,7 @@ class MusicSubsystem:
logging.exception('Error in get_soundtrack_entry_name.')
return 'default'
def on_app_resume(self) -> None:
def on_app_unsuspend(self) -> None:
"""Should be run when the app resumes from a suspended state."""
if babase.is_os_playing_music():
self.do_play_music(None)

View file

@ -423,6 +423,10 @@ class ServerController:
bascenev1.set_public_party_stats_url(self._config.stats_url)
bascenev1.set_public_party_enabled(self._config.party_is_public)
bascenev1.set_player_rejoin_cooldown(
self._config.player_rejoin_cooldown
)
# And here.. we.. go.
if self._config.stress_test_players is not None:
# Special case: run a stress test.

View file

@ -229,12 +229,12 @@ class ClassicSubsystem(babase.AppSubsystem):
self.accounts.on_app_loading()
def on_app_pause(self) -> None:
self.accounts.on_app_pause()
def on_app_suspend(self) -> None:
self.accounts.on_app_suspend()
def on_app_resume(self) -> None:
self.accounts.on_app_resume()
self.music.on_app_resume()
def on_app_unsuspend(self) -> None:
self.accounts.on_app_unsuspend()
self.music.on_app_unsuspend()
def on_app_shutdown(self) -> None:
self.music.on_app_shutdown()
@ -451,15 +451,6 @@ class ClassicSubsystem(babase.AppSubsystem):
if playtype in val.get_play_types()
)
def show_online_score_ui(
self,
show: str = 'general',
game: str | None = None,
game_version: str | None = None,
) -> None:
"""(internal)"""
bauiv1.show_online_score_ui(show, game, game_version)
def game_begin_analytics(self) -> None:
"""(internal)"""
from baclassic import _analytics
@ -627,15 +618,6 @@ class ClassicSubsystem(babase.AppSubsystem):
"""(internal)"""
return bascenev1.get_foreground_host_activity()
def show_config_error_window(self) -> bool:
"""(internal)"""
if self.platform in ('mac', 'linux', 'windows'):
from bauiv1lib.configerror import ConfigErrorWindow
babase.pushcall(ConfigErrorWindow)
return True
return False
def value_test(
self,
arg: str,
@ -701,11 +683,11 @@ class ClassicSubsystem(babase.AppSubsystem):
ShowURLWindow(address)
def quit_window(self) -> None:
def quit_window(self, quit_type: babase.QuitType) -> None:
"""(internal)"""
from bauiv1lib.confirm import QuitWindow
QuitWindow()
QuitWindow(quit_type)
def tournament_entry_window(
self,
@ -809,5 +791,6 @@ class ClassicSubsystem(babase.AppSubsystem):
bauiv1.getsound('swish').play()
babase.app.ui_v1.set_main_menu_window(
MainMenuWindow().get_root_widget()
MainMenuWindow().get_root_widget(),
from_window=False, # Disable check here.
)

View file

@ -80,14 +80,13 @@ class _MacMusicAppThread(threading.Thread):
def run(self) -> None:
"""Run the Music.app thread."""
babase.set_thread_name('BA_MacMusicAppThread')
babase.mac_music_app_init()
# Let's mention to the user we're launching Music.app in case
# it causes any funny business (this used to background the app
# sometimes, though I think that is fixed now)
def do_print() -> None:
babase.apptimer(
1.0,
0.5,
babase.Call(
babase.screenmessage,
babase.Lstr(resource='usingItunesText'),
@ -97,9 +96,8 @@ class _MacMusicAppThread(threading.Thread):
babase.pushcall(do_print, from_other_thread=True)
# Here we grab this to force the actual launch.
babase.mac_music_app_get_volume()
babase.mac_music_app_get_library_source()
babase.mac_music_app_init()
done = False
while not done:
self._commands_available.wait()

View file

@ -5,22 +5,49 @@
from __future__ import annotations
from enum import Enum
from typing import TYPE_CHECKING
from dataclasses import dataclass
from typing import TYPE_CHECKING, Annotated
from efro.dataclassio import ioprepped, IOAttrs
if TYPE_CHECKING:
pass
class AppExperience(Enum):
"""Overall experience that can be provided by a Ballistica app.
class AppInterfaceIdiom(Enum):
"""A general form-factor or way of experiencing a Ballistica app.
This corresponds generally, but not exactly, to distinct apps built
with Ballistica. However, a single app may support multiple experiences,
or there may be multiple apps targeting one experience. Cloud components
such as leagues are generally associated with an AppExperience.
Note that it is possible for a running app to switch idioms (for
instance if a mobile device or computer is connected to a TV).
"""
# A special experience category that is supported everywhere. Used
PHONE = 'phone'
TABLET = 'tablet'
DESKTOP = 'desktop'
TV = 'tv'
XR = 'xr'
class AppExperience(Enum):
"""A particular experience that can be provided by a Ballistica app.
This is one metric used to isolate different playerbases from
eachother where there might be no technical barriers doing so.
For example, a casual one-hand-playable phone game and an augmented
reality tabletop game may both use the same scene-versions and
networking-protocols and whatnot, but it would make no sense to
allow players of one join servers for the other. AppExperience can
be used to keep these player bases separate.
Generally a single Ballistica app targets a single AppExperience.
This is not a technical requirement, however. A single app may
support multiple experiences, or there may be multiple apps
targeting one experience. Cloud components such as leagues are
generally associated with an AppExperience so that they are only
visible to client apps designed for that play style.
"""
# An experience that is supported everywhere. Used
# for the default empty AppMode when starting the app, etc.
EMPTY = 'empty'
@ -33,3 +60,79 @@ class AppExperience(Enum):
# touch-screen allowing a mobile device to be used as a game
# controller.
REMOTE = 'remote'
class AppArchitecture(Enum):
"""Processor architecture the App is running on."""
ARM = 'arm'
ARM64 = 'arm64'
X86 = 'x86'
X86_64 = 'x86_64'
class AppPlatform(Enum):
"""Overall platform a Ballistica build can be targeting.
Each distinct flavor of an app has a unique combination
of AppPlatform and AppVariant. Generally platform describes
a set of hardware, while variant describes a destination or
purpose for the build.
"""
MAC = 'mac'
WINDOWS = 'windows'
LINUX = 'linux'
ANDROID = 'android'
IOS = 'ios'
TVOS = 'tvos'
class AppVariant(Enum):
"""A unique Ballistica build type within a single platform.
Each distinct flavor of an app has a unique combination
of AppPlatform and AppVariant. Generally platform describes
a set of hardware, while variant describes a destination or
purpose for the build.
"""
# Default builds.
GENERIC = 'generic'
# Builds intended for public testing (may have some extra checks
# or logging enabled).
TEST = 'test'
# Various stores.
AMAZON_APPSTORE = 'amazon_appstore'
GOOGLE_PLAY = 'google_play'
APP_STORE = 'app_store'
WINDOWS_STORE = 'windows_store'
STEAM = 'steam'
META = 'meta'
EPIC_GAMES_STORE = 'epic_games_store'
# Other.
ARCADE = 'arcade'
DEMO = 'demo'
@ioprepped
@dataclass
class AppInstanceInfo:
"""General info about an individual running app."""
name = Annotated[str, IOAttrs('n')]
version = Annotated[str, IOAttrs('v')]
build = Annotated[int, IOAttrs('b')]
platform = Annotated[AppPlatform, IOAttrs('p')]
variant = Annotated[AppVariant, IOAttrs('va')]
architecture = Annotated[AppArchitecture, IOAttrs('a')]
os_version = Annotated[str | None, IOAttrs('o')]
interface_idiom: Annotated[AppInterfaceIdiom, IOAttrs('i')]
locale: Annotated[str, IOAttrs('l')]
device: Annotated[str | None, IOAttrs('d')]

View file

@ -11,6 +11,12 @@ if TYPE_CHECKING:
pass
# NOTE TO SELF:
# Whenever adding login types here, make sure to update all
# basn nodes before trying to send values through to bamaster,
# as they need to be extractable by basn en route.
class LoginType(Enum):
"""Types of logins available."""
@ -20,6 +26,9 @@ class LoginType(Enum):
# Google Play Game Services
GPGS = 'gpgs'
# Apple's Game Center
GAME_CENTER = 'game_center'
@property
def displayname(self) -> str:
"""Human readable name for this value."""
@ -29,3 +38,5 @@ class LoginType(Enum):
return 'Email/Password'
case cls.GPGS:
return 'Google Play Games'
case cls.GAME_CENTER:
return 'Game Center'

View file

@ -143,9 +143,20 @@ class ServerConfig:
# queue spamming attacks.
enable_queue: bool = True
# Protocol version we host with. Currently the default is 33 which
# still allows older 1.4 game clients to connect. Explicitly setting
# to 35 no longer allows those clients but adds/fixes a few things
# such as making camera shake properly work in net games.
protocol_version: int | None = None
# (internal) stress-testing mode.
stress_test_players: int | None = None
# How many seconds individual players from a given account must wait
# before rejoining the game. This can help suppress exploits
# involving leaving and rejoining or switching teams rapidly.
player_rejoin_cooldown: float = 10.0
# NOTE: as much as possible, communication from the server-manager to the
# child-process should go through these and not ad-hoc Python string commands

View file

@ -40,7 +40,7 @@ if TYPE_CHECKING:
# the last load. Either way, however, multiple execs will happen in some
# form.
#
# So we need to do a few things to handle that situation gracefully.
# To handle that situation gracefully, we need to do a few things:
#
# - First, we need to store any mutable global state in the __main__
# module; not in ourself. This way, alternate versions of ourself will
@ -48,12 +48,12 @@ if TYPE_CHECKING:
#
# - Second, we should avoid the use of isinstance and similar calls for
# our types. An EnvConfig we create would technically be a different
# type than that created by an alternate baenv.
# type than an EnvConfig created by an alternate baenv.
# Build number and version of the ballistica binary we expect to be
# using.
TARGET_BALLISTICA_BUILD = 21397
TARGET_BALLISTICA_VERSION = '1.7.28'
TARGET_BALLISTICA_BUILD = 21739
TARGET_BALLISTICA_VERSION = '1.7.32'
@dataclass

View file

@ -1,6 +1,6 @@
# Released under the MIT License. See LICENSE for details.
#
"""Provides classic app subsystem."""
"""Provides plus app subsystem."""
from __future__ import annotations
from typing import TYPE_CHECKING
@ -249,3 +249,41 @@ class PlusSubsystem(AppSubsystem):
) -> None:
"""(internal)"""
return _baplus.tournament_query(callback, args)
@staticmethod
def have_incentivized_ad() -> bool:
"""Is an incentivized ad available?"""
return _baplus.have_incentivized_ad()
@staticmethod
def has_video_ads() -> bool:
"""Are video ads available?"""
return _baplus.has_video_ads()
@staticmethod
def can_show_ad() -> bool:
"""Can we show an ad?"""
return _baplus.can_show_ad()
@staticmethod
def show_ad(
purpose: str, on_completion_call: Callable[[], None] | None = None
) -> None:
"""Show an ad."""
_baplus.show_ad(purpose, on_completion_call)
@staticmethod
def show_ad_2(
purpose: str, on_completion_call: Callable[[bool], None] | None = None
) -> None:
"""Show an ad."""
_baplus.show_ad_2(purpose, on_completion_call)
@staticmethod
def show_game_service_ui(
show: str = 'general',
game: str | None = None,
game_version: str | None = None,
) -> None:
"""Show game-service provided UI."""
_baplus.show_game_service_ui(show, game, game_version)

View file

@ -78,6 +78,7 @@ from _bascenev1 import (
end_host_scanning,
get_chat_messages,
get_connection_to_host_info,
get_connection_to_host_info_2,
get_foreground_host_activity,
get_foreground_host_session,
get_game_port,
@ -202,6 +203,7 @@ from bascenev1._multiteamsession import (
DEFAULT_TEAM_NAMES,
)
from bascenev1._music import MusicType, setmusic
from bascenev1._net import HostInfo
from bascenev1._nodeactor import NodeActor
from bascenev1._powerup import get_default_powerup_distribution
from bascenev1._profile import (
@ -226,7 +228,7 @@ from bascenev1._settings import (
IntSetting,
Setting,
)
from bascenev1._session import Session
from bascenev1._session import Session, set_player_rejoin_cooldown
from bascenev1._stats import PlayerScoredMessage, PlayerRecord, Stats
from bascenev1._team import SessionTeam, Team, EmptyTeam
from bascenev1._teamgame import TeamGameActivity
@ -303,6 +305,7 @@ __all__ = [
'GameTip',
'get_chat_messages',
'get_connection_to_host_info',
'get_connection_to_host_info_2',
'get_default_free_for_all_playlist',
'get_default_teams_playlist',
'get_default_powerup_distribution',
@ -338,6 +341,7 @@ __all__ = [
'have_connected_clients',
'have_touchscreen_input',
'HitMessage',
'HostInfo',
'host_scan_cycle',
'ImpactDamageMessage',
'increment_analytics_count',
@ -415,6 +419,7 @@ __all__ = [
'set_public_party_name',
'set_public_party_queue_enabled',
'set_public_party_stats_url',
'set_player_rejoin_cooldown',
'set_replay_speed_exponent',
'set_touchscreen_editing',
'setmusic',

View file

@ -87,7 +87,9 @@ class Campaign:
def get_selected_level(self) -> str:
"""Return the name of the Level currently selected in the UI."""
return self.configdict.get('Selection', self._levels[0].name)
val = self.configdict.get('Selection', self._levels[0].name)
assert isinstance(val, str)
return val
@property
def configdict(self) -> dict[str, Any]:

View file

@ -438,10 +438,16 @@ class GameActivity(Activity[PlayerT, TeamT]):
assert classic is not None
continues_window = classic.continues_window
# Turning these off. I want to migrate towards monetization that
# feels less pay-to-win-ish.
allow_continues = False
plus = babase.app.plus
try:
if plus is not None and plus.get_v1_account_misc_read_val(
'enableContinues', False
if (
plus is not None
and plus.get_v1_account_misc_read_val('enableContinues', False)
and allow_continues
):
session = self.session

View file

@ -105,7 +105,9 @@ class Level:
def complete(self) -> bool:
"""Whether this Level has been completed."""
config = self._get_config_dict()
return config.get('Complete', False)
val = config.get('Complete', False)
assert isinstance(val, bool)
return val
def set_complete(self, val: bool) -> None:
"""Set whether or not this level is complete."""
@ -147,7 +149,9 @@ class Level:
@property
def rating(self) -> float:
"""The current rating for this Level."""
return self._get_config_dict().get('Rating', 0.0)
val = self._get_config_dict().get('Rating', 0.0)
assert isinstance(val, float)
return val
def set_rating(self, rating: float) -> None:
"""Set a rating for this Level, replacing the old ONLY IF higher."""

View file

@ -170,8 +170,11 @@ class MultiTeamSession(Session):
def get_max_players(self) -> int:
"""Return max number of Players allowed to join the game at once."""
if self.use_teams:
return babase.app.config.get('Team Game Max Players', 8)
return babase.app.config.get('Free-for-All Max Players', 8)
val = babase.app.config.get('Team Game Max Players', 8)
else:
val = babase.app.config.get('Free-for-All Max Players', 8)
assert isinstance(val, int)
return val
def _instantiate_next_game(self) -> None:
self._next_game_instance = _bascenev1.newactivity(

24
dist/ba_data/python/bascenev1/_net.py vendored Normal file
View file

@ -0,0 +1,24 @@
# Released under the MIT License. See LICENSE for details.
#
"""Functionality related to net play."""
from __future__ import annotations
from typing import TYPE_CHECKING
from dataclasses import dataclass
if TYPE_CHECKING:
pass
@dataclass
class HostInfo:
"""Info about a host."""
name: str
build_number: int
# Note this can be None for non-ip hosts such as bluetooth.
address: str | None
# Note this can be None for non-ip hosts such as bluetooth.
port: int | None

View file

@ -3,6 +3,7 @@
"""Defines base session class."""
from __future__ import annotations
import math
import weakref
import logging
from typing import TYPE_CHECKING
@ -17,6 +18,17 @@ if TYPE_CHECKING:
import bascenev1
# How many seconds someone who left the session (but not the party) must
# wait to rejoin the session again. Intended to prevent game exploits
# such as skipping respawn waits.
_g_player_rejoin_cooldown: float = 0.0
def set_player_rejoin_cooldown(cooldown: float) -> None:
"""Set the cooldown for individual players rejoining after leaving."""
global _g_player_rejoin_cooldown # pylint: disable=global-statement
_g_player_rejoin_cooldown = max(0.0, cooldown)
class Session:
"""Defines a high level series of bascenev1.Activity-es.
@ -203,6 +215,11 @@ class Session:
# Instantiate our session globals node which will apply its settings.
self._sessionglobalsnode = _bascenev1.newnode('sessionglobals')
# Rejoin cooldown stuff.
self._players_on_wait: dict = {}
self._player_requested_identifiers: dict = {}
self._waitlist_timers: dict = {}
@property
def context(self) -> bascenev1.ContextRef:
"""A context-ref pointing at this activity."""
@ -253,6 +270,33 @@ class Session:
)
return False
# Rejoin cooldown.
identifier = player.get_v1_account_id()
if identifier:
leave_time = self._players_on_wait.get(identifier)
if leave_time:
diff = str(
math.ceil(
_g_player_rejoin_cooldown
- babase.apptime()
+ leave_time
)
)
_bascenev1.broadcastmessage(
babase.Lstr(
translate=(
'serverResponses',
'You can join in ${COUNT} seconds.',
),
subs=[('${COUNT}', diff)],
),
color=(1, 1, 0),
clients=[player.inputdevice.client_id],
transient=True,
)
return False
self._player_requested_identifiers[player.id] = identifier
_bascenev1.getsound('dripity').play()
return True
@ -270,6 +314,16 @@ class Session:
activity = self._activity_weak()
# Rejoin cooldown.
identifier = self._player_requested_identifiers.get(sessionplayer.id)
if identifier:
self._players_on_wait[identifier] = babase.apptime()
with babase.ContextRef.empty():
self._waitlist_timers[identifier] = babase.AppTimer(
_g_player_rejoin_cooldown,
babase.Call(self._remove_player_from_waitlist, identifier),
)
if not sessionplayer.in_game:
# Ok, the player is still in the lobby; simply remove them.
with self.context:
@ -770,3 +824,9 @@ class Session:
if pass_to_activity:
activity.add_player(sessionplayer)
return sessionplayer
def _remove_player_from_waitlist(self, identifier: str) -> None:
try:
self._players_on_wait.pop(identifier)
except KeyError:
pass

View file

@ -9,6 +9,7 @@ import random
import logging
from typing import TYPE_CHECKING
from bacommon.login import LoginType
import bascenev1 as bs
import bauiv1 as bui
@ -59,29 +60,25 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
)
)
self._account_type = (
plus.get_v1_account_type()
if plus.get_v1_account_state() == 'signed_in'
else None
)
self._game_service_icon_color: Sequence[float] | None
self._game_service_achievements_texture: bui.Texture | None
self._game_service_leaderboards_texture: bui.Texture | None
if self._account_type == 'Game Center':
# Tie in to specific game services if they are active.
adapter = plus.accounts.login_adapters.get(LoginType.GPGS)
gpgs_active = adapter is not None and adapter.is_back_end_active()
adapter = plus.accounts.login_adapters.get(LoginType.GAME_CENTER)
game_center_active = (
adapter is not None and adapter.is_back_end_active()
)
if game_center_active:
self._game_service_icon_color = (1.0, 1.0, 1.0)
icon = bui.gettexture('gameCenterIcon')
self._game_service_achievements_texture = icon
self._game_service_leaderboards_texture = icon
self._account_has_achievements = True
elif self._account_type == 'Game Circle':
icon = bui.gettexture('gameCircleIcon')
self._game_service_icon_color = (1, 1, 1)
self._game_service_achievements_texture = icon
self._game_service_leaderboards_texture = icon
self._account_has_achievements = True
elif self._account_type == 'Google Play':
elif gpgs_active:
self._game_service_icon_color = (0.8, 1.0, 0.6)
self._game_service_achievements_texture = bui.gettexture(
'googlePlayAchievementsIcon'
@ -193,7 +190,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
super().__del__()
# If our UI is still up, kill it.
if self._root_ui:
if self._root_ui and not self._root_ui.transitioning_out:
with bui.ContextRef.empty():
bui.containerwidget(edit=self._root_ui, transition='out_left')
@ -287,20 +284,20 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
self.end({'outcome': 'next_level'})
def _ui_gc(self) -> None:
if bs.app.classic is not None:
bs.app.classic.show_online_score_ui(
if bs.app.plus is not None:
bs.app.plus.show_game_service_ui(
'leaderboard',
game=self._game_name_str,
game_version=self._game_config_str,
)
else:
logging.warning('show_online_score_ui requires classic')
logging.warning('show_game_service_ui requires plus feature-set')
def _ui_show_achievements(self) -> None:
if bs.app.classic is not None:
bs.app.classic.show_online_score_ui('achievements')
if bs.app.plus is not None:
bs.app.plus.show_game_service_ui('achievements')
else:
logging.warning('show_online_score_ui requires classic')
logging.warning('show_game_service_ui requires plus feature-set')
def _ui_worlds_best(self) -> None:
if self._score_link is None:

View file

@ -35,7 +35,7 @@ class ControlsGuide(bs.Actor):
delay: is the time in seconds before the overlay fades in.
lifespan: if not None, the overlay will fade back out and die after
that long (in milliseconds).
that long (in seconds).
bright: if True, brighter colors will be used; handy when showing
over gameplay but may be too bright for join-screens, etc.
@ -50,6 +50,7 @@ class ControlsGuide(bs.Actor):
offs5 = 43.0 * scale
ouya = False
maxw = 50
xtweak = -2.8 * scale
self._lifespan = lifespan
self._dead = False
self._bright = bright
@ -117,7 +118,7 @@ class ControlsGuide(bs.Actor):
'host_only': True,
'shadow': 1.0,
'maxwidth': maxw,
'position': (pos[0], pos[1] - offs5),
'position': (pos[0] + xtweak, pos[1] - offs5),
'color': clr,
},
)
@ -145,7 +146,7 @@ class ControlsGuide(bs.Actor):
'host_only': True,
'shadow': 1.0,
'maxwidth': maxw,
'position': (pos[0], pos[1] - offs5),
'position': (pos[0] + xtweak, pos[1] - offs5),
'color': clr,
},
)
@ -173,7 +174,7 @@ class ControlsGuide(bs.Actor):
'host_only': True,
'shadow': 1.0,
'maxwidth': maxw,
'position': (pos[0], pos[1] - offs5),
'position': (pos[0] + xtweak, pos[1] - offs5),
'color': clr,
},
)
@ -201,7 +202,7 @@ class ControlsGuide(bs.Actor):
'host_only': True,
'shadow': 1.0,
'maxwidth': maxw,
'position': (pos[0], pos[1] - offs5),
'position': (pos[0] + xtweak, pos[1] - offs5),
'color': clr,
},
)
@ -264,10 +265,19 @@ class ControlsGuide(bs.Actor):
bs.timer(delay, bs.WeakCall(self._start_updating))
@staticmethod
def _meaningful_button_name(device: bs.InputDevice, button: int) -> str:
def _meaningful_button_name(
device: bs.InputDevice, button_name: str
) -> str:
"""Return a flattened string button name; empty for non-meaningful."""
if not device.has_meaningful_button_names:
return ''
assert bs.app.classic is not None
button = bs.app.classic.get_input_device_mapped_value(
device, button_name
)
# -1 means unset; let's show that.
if button == -1:
return bs.Lstr(resource='configGamepadWindow.unsetText').evaluate()
return device.get_button_name(button).evaluate()
def _start_updating(self) -> None:
@ -289,10 +299,10 @@ class ControlsGuide(bs.Actor):
def _check_fade_in(self) -> None:
assert bs.app.classic is not None
# If we have a touchscreen, we only fade in if we have a player with
# an input device that is *not* the touchscreen.
# (otherwise it is confusing to see the touchscreen buttons right
# next to our display buttons)
# If we have a touchscreen, we only fade in if we have a player
# with an input device that is *not* the touchscreen. Otherwise
# it is confusing to see the touchscreen buttons right next to
# our display buttons.
touchscreen: bs.InputDevice | None = bs.getinputdevice(
'TouchScreen', '#1', doraise=False
)
@ -318,15 +328,7 @@ class ControlsGuide(bs.Actor):
'buttonBomb',
'buttonPickUp',
):
if (
self._meaningful_button_name(
device,
bs.app.classic.get_input_device_mapped_value(
device, name
),
)
!= ''
):
if self._meaningful_button_name(device, name) != '':
fade_in = True
break
if fade_in:
@ -401,58 +403,30 @@ class ControlsGuide(bs.Actor):
# We only care about movement buttons in the case of keyboards.
if all_keyboards:
right_button_names.add(
device.get_button_name(
classic.get_input_device_mapped_value(
device, 'buttonRight'
)
)
self._meaningful_button_name(device, 'buttonRight')
)
left_button_names.add(
device.get_button_name(
classic.get_input_device_mapped_value(
device, 'buttonLeft'
)
)
self._meaningful_button_name(device, 'buttonLeft')
)
down_button_names.add(
device.get_button_name(
classic.get_input_device_mapped_value(
device, 'buttonDown'
)
)
self._meaningful_button_name(device, 'buttonDown')
)
up_button_names.add(
device.get_button_name(
classic.get_input_device_mapped_value(
device, 'buttonUp'
)
)
self._meaningful_button_name(device, 'buttonUp')
)
# Ignore empty values; things like the remote app or
# wiimotes can return these.
bname = self._meaningful_button_name(
device,
classic.get_input_device_mapped_value(device, 'buttonPunch'),
)
bname = self._meaningful_button_name(device, 'buttonPunch')
if bname != '':
punch_button_names.add(bname)
bname = self._meaningful_button_name(
device,
classic.get_input_device_mapped_value(device, 'buttonJump'),
)
bname = self._meaningful_button_name(device, 'buttonJump')
if bname != '':
jump_button_names.add(bname)
bname = self._meaningful_button_name(
device,
classic.get_input_device_mapped_value(device, 'buttonBomb'),
)
bname = self._meaningful_button_name(device, 'buttonBomb')
if bname != '':
bomb_button_names.add(bname)
bname = self._meaningful_button_name(
device,
classic.get_input_device_mapped_value(device, 'buttonPickUp'),
)
bname = self._meaningful_button_name(device, 'buttonPickUp')
if bname != '':
pickup_button_names.add(bname)
@ -582,8 +556,8 @@ class ControlsGuide(bs.Actor):
if msg.immediate:
self._die()
else:
# If they don't need immediate,
# fade out our nodes and die later.
# If they don't need immediate, fade out our nodes and
# die later.
for node in self._nodes:
bs.animate(node, 'opacity', {0: node.opacity, 3.0: 0.0})
bs.timer(3.1, bs.WeakCall(self._die))

View file

@ -41,17 +41,17 @@ class Spawner:
self,
spawner: Spawner,
data: Any,
pt: Sequence[float], # pylint: disable=invalid-name
pt: Sequence[float],
):
"""Instantiate with the given values."""
self.spawner = spawner
self.data = data
self.pt = pt # pylint: disable=invalid-name
self.pt = pt
def __init__(
self,
data: Any = None,
pt: Sequence[float] = (0, 0, 0), # pylint: disable=invalid-name
pt: Sequence[float] = (0, 0, 0),
spawn_time: float = 1.0,
send_spawn_message: bool = True,
spawn_callback: Callable[[], Any] | None = None,

View file

@ -624,7 +624,7 @@ class Spaz(bs.Actor):
1000.0 * (tval + self.curse_time)
)
self._curse_timer = bs.Timer(
5.0, bs.WeakCall(self.curse_explode)
5.0, bs.WeakCall(self.handlemessage, CurseExplodeMessage())
)
def equip_boxing_gloves(self) -> None:
@ -1136,7 +1136,7 @@ class Spaz(bs.Actor):
if self.hitpoints > 0:
# It's kinda crappy to die from impacts, so lets reduce
# impact damage by a reasonable amount *if* it'll keep us alive.
if msg.hit_type == 'impact' and damage > self.hitpoints:
if msg.hit_type == 'impact' and damage >= self.hitpoints:
# Drop damage to whatever puts us at 10 hit points,
# or 200 less than it used to be whichever is greater
# (so it *can* still kill us if its high enough).

View file

@ -122,7 +122,6 @@ def register_appearances() -> None:
"""Register our builtin spaz appearances."""
# This is quite ugly but will be going away so not worth cleaning up.
# pylint: disable=invalid-name
# pylint: disable=too-many-locals
# pylint: disable=too-many-statements

View file

@ -14,13 +14,12 @@ from bascenev1lib.actor.flag import Flag
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor.respawnicon import RespawnIcon
import bascenev1 as bs
if TYPE_CHECKING:
from typing import Any, Sequence
from bascenev1lib.actor.respawnicon import RespawnIcon
class ConquestFlag(Flag):
"""A custom flag for use with Conquest games."""
@ -49,7 +48,9 @@ class Player(bs.Player['Team']):
@property
def respawn_timer(self) -> bs.Timer | None:
"""Type safe access to standard respawn timer."""
return self.customdata.get('respawn_timer', None)
val = self.customdata.get('respawn_timer', None)
assert isinstance(val, (bs.Timer, type(None)))
return val
@respawn_timer.setter
def respawn_timer(self, value: bs.Timer | None) -> None:
@ -58,7 +59,9 @@ class Player(bs.Player['Team']):
@property
def respawn_icon(self) -> RespawnIcon | None:
"""Type safe access to standard respawn icon."""
return self.customdata.get('respawn_icon', None)
val = self.customdata.get('respawn_icon', None)
assert isinstance(val, (RespawnIcon, type(None)))
return val
@respawn_icon.setter
def respawn_icon(self, value: RespawnIcon | None) -> None:

View file

@ -300,7 +300,10 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
from bauiv1lib import specialoffer
assert bs.app.classic is not None
if bool(False):
if bui.app.env.headless:
# UI stuff fails now in headless builds; avoid it.
pass
elif bool(False):
uicontroller = bs.app.ui_v1.controller
assert uicontroller is not None
uicontroller.show_main_menu()
@ -314,7 +317,8 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
from bauiv1lib.kiosk import KioskWindow
bs.app.ui_v1.set_main_menu_window(
KioskWindow().get_root_widget()
KioskWindow().get_root_widget(),
from_window=False, # Disable check here.
)
# ..or in normal cases go back to the main menu
else:
@ -323,14 +327,16 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
from bauiv1lib.gather import GatherWindow
bs.app.ui_v1.set_main_menu_window(
GatherWindow(transition=None).get_root_widget()
GatherWindow(transition=None).get_root_widget(),
from_window=False, # Disable check here.
)
elif main_menu_location == 'Watch':
# pylint: disable=cyclic-import
from bauiv1lib.watch import WatchWindow
bs.app.ui_v1.set_main_menu_window(
WatchWindow(transition=None).get_root_widget()
WatchWindow(transition=None).get_root_widget(),
from_window=False, # Disable check here.
)
elif main_menu_location == 'Team Game Select':
# pylint: disable=cyclic-import
@ -341,7 +347,8 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
bs.app.ui_v1.set_main_menu_window(
PlaylistBrowserWindow(
sessiontype=bs.DualTeamSession, transition=None
).get_root_widget()
).get_root_widget(),
from_window=False, # Disable check here.
)
elif main_menu_location == 'Free-for-All Game Select':
# pylint: disable=cyclic-import
@ -353,28 +360,34 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
PlaylistBrowserWindow(
sessiontype=bs.FreeForAllSession,
transition=None,
).get_root_widget()
).get_root_widget(),
from_window=False, # Disable check here.
)
elif main_menu_location == 'Coop Select':
# pylint: disable=cyclic-import
from bauiv1lib.coop.browser import CoopBrowserWindow
bs.app.ui_v1.set_main_menu_window(
CoopBrowserWindow(transition=None).get_root_widget()
CoopBrowserWindow(
transition=None
).get_root_widget(),
from_window=False, # Disable check here.
)
elif main_menu_location == 'Benchmarks & Stress Tests':
# pylint: disable=cyclic-import
from bauiv1lib.debug import DebugWindow
bs.app.ui_v1.set_main_menu_window(
DebugWindow(transition=None).get_root_widget()
DebugWindow(transition=None).get_root_widget(),
from_window=False, # Disable check here.
)
else:
# pylint: disable=cyclic-import
from bauiv1lib.mainmenu import MainMenuWindow
bs.app.ui_v1.set_main_menu_window(
MainMenuWindow(transition=None).get_root_widget()
MainMenuWindow(transition=None).get_root_widget(),
from_window=None,
)
# attempt to show any pending offers immediately.

View file

@ -8,7 +8,6 @@
# pylint: disable=too-many-statements
# pylint: disable=too-many-lines
# pylint: disable=missing-function-docstring, missing-class-docstring
# pylint: disable=invalid-name
# pylint: disable=too-many-locals
# pylint: disable=unused-argument
# pylint: disable=unused-variable

View file

@ -31,7 +31,10 @@ from babase import (
apptimer,
AppTimer,
Call,
can_toggle_fullscreen,
fullscreen_control_available,
fullscreen_control_get,
fullscreen_control_key_shortcut,
fullscreen_control_set,
charstr,
clipboard_is_supported,
clipboard_set_text,
@ -57,18 +60,21 @@ from babase import (
in_logic_thread,
increment_analytics_count,
is_browser_likely_available,
is_running_on_fire_tv,
is_xcode_build,
Keyboard,
lock_all_input,
LoginAdapter,
LoginInfo,
Lstr,
native_review_request,
native_review_request_supported,
NotFoundError,
open_file_externally,
Permission,
Plugin,
PluginSpec,
pushcall,
quit,
QuitType,
request_permission,
safecolor,
screenmessage,
@ -87,7 +93,6 @@ from babase import (
from _bauiv1 import (
buttonwidget,
can_show_ad,
checkboxwidget,
columnwidget,
containerwidget,
@ -96,21 +101,15 @@ from _bauiv1 import (
getmesh,
getsound,
gettexture,
has_video_ads,
have_incentivized_ad,
hscrollwidget,
imagewidget,
is_party_icon_visible,
Mesh,
open_file_externally,
open_url,
rowwidget,
scrollwidget,
set_party_icon_always_visible,
set_party_window_open,
show_ad,
show_ad_2,
show_online_score_ui,
Sound,
Texture,
textwidget,
@ -118,6 +117,7 @@ from _bauiv1 import (
Widget,
widget,
)
from bauiv1._keyboard import Keyboard
from bauiv1._uitypes import Window, uicleanupcheck
from bauiv1._subsystem import UIV1Subsystem
@ -137,8 +137,10 @@ __all__ = [
'AppTimer',
'buttonwidget',
'Call',
'can_show_ad',
'can_toggle_fullscreen',
'fullscreen_control_available',
'fullscreen_control_get',
'fullscreen_control_key_shortcut',
'fullscreen_control_set',
'charstr',
'checkboxwidget',
'clipboard_is_supported',
@ -168,8 +170,6 @@ __all__ = [
'getmesh',
'getsound',
'gettexture',
'has_video_ads',
'have_incentivized_ad',
'have_permission',
'hscrollwidget',
'imagewidget',
@ -177,13 +177,15 @@ __all__ = [
'increment_analytics_count',
'is_browser_likely_available',
'is_party_icon_visible',
'is_running_on_fire_tv',
'is_xcode_build',
'Keyboard',
'lock_all_input',
'LoginAdapter',
'LoginInfo',
'Lstr',
'Mesh',
'native_review_request',
'native_review_request_supported',
'NotFoundError',
'open_file_externally',
'open_url',
@ -192,6 +194,7 @@ __all__ = [
'PluginSpec',
'pushcall',
'quit',
'QuitType',
'request_permission',
'rowwidget',
'safecolor',
@ -202,9 +205,6 @@ __all__ = [
'set_party_icon_always_visible',
'set_party_window_open',
'set_ui_input_device',
'show_ad',
'show_ad_2',
'show_online_score_ui',
'Sound',
'SpecialChar',
'supports_max_fps',

View file

@ -6,6 +6,7 @@
from __future__ import annotations
import logging
import inspect
from typing import TYPE_CHECKING
import _bauiv1
@ -13,6 +14,8 @@ import _bauiv1
if TYPE_CHECKING:
from typing import Sequence
import babase
def ticket_icon_press() -> None:
from babase import app
@ -57,14 +60,14 @@ def party_icon_activate(origin: Sequence[float]) -> None:
logging.warning('party_icon_activate: no classic.')
def quit_window() -> None:
def quit_window(quit_type: babase.QuitType) -> None:
from babase import app
if app.classic is None:
logging.exception('Classic not present.')
return
app.classic.quit_window()
app.classic.quit_window(quit_type)
def device_menu_press(device_id: int | None) -> None:
@ -85,3 +88,19 @@ def show_url_window(address: str) -> None:
return
app.classic.show_url_window(address)
def double_transition_out_warning() -> None:
"""Called if a widget is set to transition out twice."""
caller_frame = inspect.stack()[1]
caller_filename = caller_frame.filename
caller_line_number = caller_frame.lineno
logging.warning(
'ContainerWidget was set to transition out twice;'
' this often implies buggy code (%s line %s).\n'
' Generally you should check the value of'
' _root_widget.transitioning_out and perform no actions if that'
' is True.',
caller_filename,
caller_line_number,
)

33
dist/ba_data/python/bauiv1/_keyboard.py vendored Normal file
View file

@ -0,0 +1,33 @@
# Released under the MIT License. See LICENSE for details.
#
"""On-screen Keyboard related functionality."""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
pass
class Keyboard:
"""Chars definitions for on-screen keyboard.
Category: **App Classes**
Keyboards are discoverable by the meta-tag system
and the user can select which one they want to use.
On-screen keyboard uses chars from active babase.Keyboard.
"""
name: str
"""Displays when user selecting this keyboard."""
chars: list[tuple[str, ...]]
"""Used for row/column lengths."""
pages: dict[str, tuple[str, ...]]
"""Extra chars like emojis."""
nums: tuple[str, ...]
"""The 'num' page."""

View file

@ -5,6 +5,7 @@
from __future__ import annotations
import logging
import inspect
from typing import TYPE_CHECKING
import babase
@ -66,6 +67,16 @@ class UIV1Subsystem(babase.AppSubsystem):
# a more elegant way once we revamp high level UI stuff a bit.
self.selecting_private_party_playlist: bool = False
@property
def available(self) -> bool:
"""Can uiv1 currently be used?
Code that may run in headless mode, before the UI has been spun up,
while other ui systems are active, etc. can check this to avoid
likely erroring.
"""
return _bauiv1.is_available()
@property
def uiscale(self) -> babase.UIScale:
"""Current ui scale for the app."""
@ -106,21 +117,69 @@ class UIV1Subsystem(babase.AppSubsystem):
# FIXME: Can probably kill this if we do immediate UI death checks.
self.upkeeptimer = babase.AppTimer(2.6543, ui_upkeep, repeat=True)
def set_main_menu_window(self, window: bauiv1.Widget) -> None:
"""Set the current 'main' window, replacing any existing."""
def set_main_menu_window(
self,
window: bauiv1.Widget,
from_window: bauiv1.Widget | None | bool = True,
) -> None:
"""Set the current 'main' window, replacing any existing.
If 'from_window' is passed as a bauiv1.Widget or None, a warning
will be issued if it that value does not match the current main
window. This can help clean up flawed code that can lead to bad
UI states. A value of False will disable the check.
"""
existing = self._main_menu_window
from inspect import currentframe, getframeinfo
try:
if isinstance(from_window, bool):
# For default val True we warn that the arg wasn't
# passed. False can be explicitly passed to disable this
# check.
if from_window is True:
caller_frame = inspect.stack()[1]
caller_filename = caller_frame.filename
caller_line_number = caller_frame.lineno
logging.warning(
'set_main_menu_window() should be passed a'
" 'from_window' value to help ensure proper UI behavior"
' (%s line %i).',
caller_filename,
caller_line_number,
)
else:
# For everything else, warn if what they passed wasn't
# the previous main menu widget.
if from_window is not existing:
caller_frame = inspect.stack()[1]
caller_filename = caller_frame.filename
caller_line_number = caller_frame.lineno
logging.warning(
"set_main_menu_window() was passed 'from_window' %s"
' but existing main-menu-window is %s. (%s line %i).',
from_window,
existing,
caller_filename,
caller_line_number,
)
except Exception:
# Prevent any bugs in these checks from causing problems.
logging.exception('Error checking from_window')
# Once the above code leads to us fixing all leftover window bugs
# at the source, we can kill the code below.
# Let's grab the location where we were called from to report
# if we have to force-kill the existing window (which normally
# should not happen).
frameline = None
try:
frame = currentframe()
frame = inspect.currentframe()
if frame is not None:
frame = frame.f_back
if frame is not None:
frameinfo = getframeinfo(frame)
frameinfo = inspect.getframeinfo(frame)
frameline = f'{frameinfo.filename} {frameinfo.lineno}'
except Exception:
logging.exception('Error calcing line for set_main_menu_window')
@ -150,13 +209,18 @@ class UIV1Subsystem(babase.AppSubsystem):
def clear_main_menu_window(self, transition: str | None = None) -> None:
"""Clear any existing 'main' window with the provided transition."""
assert transition is None or not transition.endswith('_in')
if self._main_menu_window:
if transition is not None:
if (
transition is not None
and not self._main_menu_window.transitioning_out
):
_bauiv1.containerwidget(
edit=self._main_menu_window, transition=transition
)
else:
self._main_menu_window.delete()
self._main_menu_window = None
def add_main_menu_close_callback(self, call: Callable[[], Any]) -> None:
"""(internal)"""

View file

@ -12,6 +12,7 @@ from typing import TYPE_CHECKING
import babase
import _bauiv1
from bauiv1._keyboard import Keyboard
from bauiv1._uitypes import Window
if TYPE_CHECKING:
@ -51,6 +52,19 @@ class OnScreenKeyboardWindow(Window):
else (0, 0),
)
)
self._cancel_button = _bauiv1.buttonwidget(
parent=self._root_widget,
scale=0.5,
position=(30, self._height - 55),
size=(60, 60),
label='',
enable_sound=False,
on_activate_call=self._cancel,
autoselect=True,
color=(0.55, 0.5, 0.6),
icon=_bauiv1.gettexture('crossOut'),
iconscale=1.2,
)
self._done_button = _bauiv1.buttonwidget(
parent=self._root_widget,
position=(self._width - 200, 44),
@ -240,9 +254,7 @@ class OnScreenKeyboardWindow(Window):
# Show change instructions only if we have more than one
# keyboard option.
keyboards = (
babase.app.meta.scanresults.exports_of_class(
babase.Keyboard
)
babase.app.meta.scanresults.exports_of_class(Keyboard)
if babase.app.meta.scanresults is not None
else []
)
@ -274,10 +286,10 @@ class OnScreenKeyboardWindow(Window):
def _get_keyboard(self) -> bui.Keyboard:
assert babase.app.meta.scanresults is not None
classname = babase.app.meta.scanresults.exports_of_class(
babase.Keyboard
)[self._keyboard_index]
kbclass = babase.getclass(classname, babase.Keyboard)
classname = babase.app.meta.scanresults.exports_of_class(Keyboard)[
self._keyboard_index
]
kbclass = babase.getclass(classname, Keyboard)
return kbclass()
def _refresh(self) -> None:
@ -372,9 +384,7 @@ class OnScreenKeyboardWindow(Window):
def _next_keyboard(self) -> None:
assert babase.app.meta.scanresults is not None
kbexports = babase.app.meta.scanresults.exports_of_class(
babase.Keyboard
)
kbexports = babase.app.meta.scanresults.exports_of_class(Keyboard)
self._keyboard_index = (self._keyboard_index + 1) % len(kbexports)
self._load_keyboard()

View file

@ -63,20 +63,14 @@ class AccountSettingsWindow(bui.Window):
1.0, bui.WeakCall(self._update), repeat=True
)
# Currently we can only reset achievements on game-center.
v1_account_type: str | None
if self._v1_signed_in:
v1_account_type = plus.get_v1_account_type()
else:
v1_account_type = None
self._can_reset_achievements = v1_account_type == 'Game Center'
self._can_reset_achievements = False
app = bui.app
assert app.classic is not None
uiscale = app.ui_v1.uiscale
self._width = 760 if uiscale is bui.UIScale.SMALL else 660
x_offs = 50 if uiscale is bui.UIScale.SMALL else 0
self._width = 860 if uiscale is bui.UIScale.SMALL else 660
x_offs = 100 if uiscale is bui.UIScale.SMALL else 0
self._height = (
390
if uiscale is bui.UIScale.SMALL
@ -98,6 +92,9 @@ class AccountSettingsWindow(bui.Window):
if LoginType.GPGS in plus.accounts.login_adapters:
self._show_sign_in_buttons.append('Google Play')
if LoginType.GAME_CENTER in plus.accounts.login_adapters:
self._show_sign_in_buttons.append('Game Center')
# Always want to show our web-based v2 login option.
self._show_sign_in_buttons.append('V2Proxy')
@ -227,6 +224,8 @@ class AccountSettingsWindow(bui.Window):
plus = bui.app.plus
assert plus is not None
via_lines: list[str] = []
primary_v2_account = plus.accounts.primary
v1_state = plus.get_v1_account_state()
@ -237,14 +236,55 @@ class AccountSettingsWindow(bui.Window):
# We expose GPGS-specific functionality only if it is 'active'
# (meaning the current GPGS player matches one of our account's
# logins).
gpgs_adapter = plus.accounts.login_adapters.get(LoginType.GPGS)
is_gpgs = (
False if gpgs_adapter is None else gpgs_adapter.is_back_end_active()
adapter = plus.accounts.login_adapters.get(LoginType.GPGS)
gpgs_active = adapter is not None and adapter.is_back_end_active()
# Ditto for Game Center.
adapter = plus.accounts.login_adapters.get(LoginType.GAME_CENTER)
game_center_active = (
adapter is not None and adapter.is_back_end_active()
)
show_signed_in_as = self._v1_signed_in
signed_in_as_space = 95.0
# To reduce confusion about the whole V2 account situation for
# people used to seeing their Google Play Games or Game Center
# account name and icon and whatnot, let's show those underneath
# the V2 tag to help communicate that they are in fact logged in
# through that account.
via_space = 25.0
if show_signed_in_as and bui.app.plus is not None:
accounts = bui.app.plus.accounts
if accounts.primary is not None:
# For these login types, we show 'via' IF there is a
# login of that type attached to our account AND it is
# currently active (We don't want to show 'via Game
# Center' if we're signed out of Game Center or
# currently running on Steam, even if there is a Game
# Center login attached to our account).
for ltype, lchar in [
(LoginType.GPGS, bui.SpecialChar.GOOGLE_PLAY_GAMES_LOGO),
(LoginType.GAME_CENTER, bui.SpecialChar.GAME_CENTER_LOGO),
]:
linfo = accounts.primary.logins.get(ltype)
ladapter = accounts.login_adapters.get(ltype)
if (
linfo is not None
and ladapter is not None
and ladapter.is_back_end_active()
):
via_lines.append(f'{bui.charstr(lchar)}{linfo.name}')
# TEMP TESTING
if bool(False):
icontxt = bui.charstr(bui.SpecialChar.GAME_CENTER_LOGO)
via_lines.append(f'{icontxt}FloofDibble')
icontxt = bui.charstr(
bui.SpecialChar.GOOGLE_PLAY_GAMES_LOGO
)
via_lines.append(f'{icontxt}StinkBobble')
show_sign_in_benefits = not self._v1_signed_in
sign_in_benefits_space = 80.0
@ -258,6 +298,11 @@ class AccountSettingsWindow(bui.Window):
and self._signing_in_adapter is None
and 'Google Play' in self._show_sign_in_buttons
)
show_game_center_sign_in_button = (
v1_state == 'signed_out'
and self._signing_in_adapter is None
and 'Game Center' in self._show_sign_in_buttons
)
show_v2_proxy_sign_in_button = (
v1_state == 'signed_out'
and self._signing_in_adapter is None
@ -271,9 +316,8 @@ class AccountSettingsWindow(bui.Window):
sign_in_button_space = 70.0
deprecated_space = 60
show_game_service_button = self._v1_signed_in and v1_account_type in [
'Game Center'
]
# Game Center currently has a single UI for everything.
show_game_service_button = game_center_active
game_service_button_space = 60.0
show_what_is_v2 = self._v1_signed_in and v1_account_type == 'V2'
@ -281,11 +325,9 @@ class AccountSettingsWindow(bui.Window):
show_linked_accounts_text = self._v1_signed_in
linked_accounts_text_space = 60.0
show_achievements_button = self._v1_signed_in and v1_account_type in (
'Google Play',
'Local',
'V2',
)
# Always show achievements except in the game-center case where
# its unified UI covers them.
show_achievements_button = self._v1_signed_in and not game_center_active
achievements_button_space = 60.0
show_achievements_text = (
@ -293,7 +335,7 @@ class AccountSettingsWindow(bui.Window):
)
achievements_text_space = 27.0
show_leaderboards_button = self._v1_signed_in and is_gpgs
show_leaderboards_button = self._v1_signed_in and gpgs_active
leaderboards_button_space = 60.0
show_campaign_progress = self._v1_signed_in
@ -330,7 +372,6 @@ class AccountSettingsWindow(bui.Window):
show_sign_out_button = self._v1_signed_in and v1_account_type in [
'Local',
'Google Play',
'V2',
]
sign_out_button_space = 70.0
@ -349,10 +390,13 @@ class AccountSettingsWindow(bui.Window):
self._sub_height = 60.0
if show_signed_in_as:
self._sub_height += signed_in_as_space
self._sub_height += via_space * len(via_lines)
if show_signing_in_text:
self._sub_height += signing_in_text_space
if show_google_play_sign_in_button:
self._sub_height += sign_in_button_space
if show_game_center_sign_in_button:
self._sub_height += sign_in_button_space
if show_v2_proxy_sign_in_button:
self._sub_height += sign_in_button_space
if show_device_sign_in_button:
@ -442,20 +486,21 @@ class AccountSettingsWindow(bui.Window):
self._account_name_what_is_text = bui.textwidget(
parent=self._subcontainer,
position=(0.0, self._account_name_what_is_y),
size=(200.0, 60),
size=(220.0, 60),
text=bui.Lstr(
value='${WHAT} -->',
subs=[('${WHAT}', bui.Lstr(resource='whatIsThisText'))],
),
scale=0.6,
color=(0.3, 0.7, 0.05),
maxwidth=200.0,
maxwidth=130.0,
h_align='right',
v_align='center',
autoselect=True,
selectable=True,
on_activate_call=show_what_is_v2_page,
click_activate=True,
glow_type='uniform',
)
if first_selectable is None:
first_selectable = self._account_name_what_is_text
@ -466,6 +511,54 @@ class AccountSettingsWindow(bui.Window):
v -= signed_in_as_space * 0.4
for via in via_lines:
v -= via_space * 0.1
sscale = 0.7
swidth = (
bui.get_string_width(via, suppress_warning=True) * sscale
)
bui.textwidget(
parent=self._subcontainer,
position=(self._sub_width * 0.5, v),
size=(0, 0),
text=via,
scale=sscale,
color=(0.6, 0.6, 0.6),
flatness=1.0,
shadow=0.0,
h_align='center',
v_align='center',
)
bui.textwidget(
parent=self._subcontainer,
position=(self._sub_width * 0.5 - swidth * 0.5 - 5, v),
size=(0, 0),
text=bui.Lstr(
value='(${VIA}',
subs=[('${VIA}', bui.Lstr(resource='viaText'))],
),
scale=0.5,
color=(0.4, 0.6, 0.4, 0.5),
flatness=1.0,
shadow=0.0,
h_align='right',
v_align='center',
)
bui.textwidget(
parent=self._subcontainer,
position=(self._sub_width * 0.5 + swidth * 0.5 + 10, v),
size=(0, 0),
text=')',
scale=0.5,
color=(0.4, 0.6, 0.4, 0.5),
flatness=1.0,
shadow=0.0,
h_align='right',
v_align='center',
)
v -= via_space * 0.9
else:
self._account_name_text = None
self._account_name_what_is_text = None
@ -477,22 +570,6 @@ class AccountSettingsWindow(bui.Window):
if show_sign_in_benefits:
v -= sign_in_benefits_space
app = bui.app
assert app.classic is not None
extra: str | bui.Lstr | None
if (
app.classic.platform in ['mac', 'ios']
and app.classic.subplatform == 'appstore'
):
extra = bui.Lstr(
value='\n${S}',
subs=[
('${S}', bui.Lstr(resource='signInWithGameCenterText'))
],
)
else:
extra = ''
bui.textwidget(
parent=self._subcontainer,
position=(
@ -500,16 +577,7 @@ class AccountSettingsWindow(bui.Window):
v + sign_in_benefits_space * 0.4,
),
size=(0, 0),
text=bui.Lstr(
value='${A}${B}',
subs=[
(
'${A}',
bui.Lstr(resource=self._r + '.signInInfoText'),
),
('${B}', extra),
],
),
text=bui.Lstr(resource=self._r + '.signInInfoText'),
max_height=sign_in_benefits_space * 0.9,
scale=0.9,
color=(0.75, 0.7, 0.8),
@ -554,7 +622,13 @@ class AccountSettingsWindow(bui.Window):
(
'${B}',
bui.Lstr(
resource=self._r + '.signInWithGooglePlayText'
resource=self._r + '.signInWithText',
subs=[
(
'${SERVICE}',
bui.Lstr(resource='googlePlayText'),
)
],
),
),
],
@ -572,6 +646,48 @@ class AccountSettingsWindow(bui.Window):
bui.widget(edit=btn, show_buffer_bottom=40, show_buffer_top=100)
self._sign_in_text = None
if show_game_center_sign_in_button:
button_width = 350
v -= sign_in_button_space
self._sign_in_google_play_button = btn = bui.buttonwidget(
parent=self._subcontainer,
position=((self._sub_width - button_width) * 0.5, v - 20),
autoselect=True,
size=(button_width, 60),
# Note: Apparently Game Center is just called 'Game Center'
# in all languages. Can revisit if not true.
# https://developer.apple.com/forums/thread/725779
label=bui.Lstr(
value='${A}${B}',
subs=[
(
'${A}',
bui.charstr(bui.SpecialChar.GAME_CENTER_LOGO),
),
(
'${B}',
bui.Lstr(
resource=self._r + '.signInWithText',
subs=[('${SERVICE}', 'Game Center')],
),
),
],
),
on_activate_call=lambda: self._sign_in_press(
LoginType.GAME_CENTER
),
)
if first_selectable is None:
first_selectable = btn
if bui.app.ui_v1.use_toolbars:
bui.widget(
edit=btn,
right_widget=bui.get_special_widget('party_button'),
)
bui.widget(edit=btn, left_widget=bbtn)
bui.widget(edit=btn, show_buffer_bottom=40, show_buffer_top=100)
self._sign_in_text = None
if show_v2_proxy_sign_in_button:
button_width = 350
v -= sign_in_button_space
@ -704,7 +820,7 @@ class AccountSettingsWindow(bui.Window):
position=((self._sub_width - button_width) * 0.5, v + 30),
autoselect=True,
size=(button_width, 60),
label=bui.Lstr(resource=self._r + '.manageAccountText'),
label=bui.Lstr(resource=f'{self._r}.manageAccountText'),
color=(0.55, 0.5, 0.6),
icon=bui.gettexture('settingsIcon'),
textcolor=(0.75, 0.7, 0.8),
@ -745,10 +861,15 @@ class AccountSettingsWindow(bui.Window):
# the button to go to OS-Specific leaderboards/high-score-lists/etc.
if show_game_service_button:
button_width = 300
v -= game_service_button_space * 0.85
v1_account_type = plus.get_v1_account_type()
if v1_account_type == 'Game Center':
v1_account_type_name = bui.Lstr(resource='gameCenterText')
v -= game_service_button_space * 0.6
if game_center_active:
# Note: Apparently Game Center is just called 'Game Center'
# in all languages. Can revisit if not true.
# https://developer.apple.com/forums/thread/725779
game_service_button_label = bui.Lstr(
value=bui.charstr(bui.SpecialChar.GAME_CENTER_LOGO)
+ 'Game Center'
)
else:
raise ValueError(
"unknown account type: '" + str(v1_account_type) + "'"
@ -761,7 +882,7 @@ class AccountSettingsWindow(bui.Window):
autoselect=True,
on_activate_call=self._on_game_service_button_press,
size=(button_width, 50),
label=v1_account_type_name,
label=game_service_button_label,
)
if first_selectable is None:
first_selectable = btn
@ -771,7 +892,7 @@ class AccountSettingsWindow(bui.Window):
right_widget=bui.get_special_widget('party_button'),
)
bui.widget(edit=btn, left_widget=bbtn)
v -= game_service_button_space * 0.15
v -= game_service_button_space * 0.4
else:
self.game_service_button = None
@ -804,13 +925,15 @@ class AccountSettingsWindow(bui.Window):
autoselect=True,
icon=bui.gettexture(
'googlePlayAchievementsIcon'
if is_gpgs
if gpgs_active
else 'achievementsIcon'
),
icon_color=(0.8, 0.95, 0.7) if is_gpgs else (0.85, 0.8, 0.9),
icon_color=(0.8, 0.95, 0.7)
if gpgs_active
else (0.85, 0.8, 0.9),
on_activate_call=(
self._on_custom_achievements_press
if is_gpgs
if gpgs_active
else self._on_achievements_press
),
size=(button_width, 50),
@ -1135,19 +1258,21 @@ class AccountSettingsWindow(bui.Window):
self._needs_refresh = False
def _on_game_service_button_press(self) -> None:
if bui.app.classic is not None:
bui.app.classic.show_online_score_ui()
if bui.app.plus is not None:
bui.app.plus.show_game_service_ui()
else:
logging.warning('game service ui not available without classic.')
logging.warning(
'game-service-ui not available without plus feature-set.'
)
def _on_custom_achievements_press(self) -> None:
if bui.app.classic is not None:
if bui.app.plus is not None:
bui.apptimer(
0.15,
bui.Call(bui.app.classic.show_online_score_ui, 'achievements'),
bui.Call(bui.app.plus.show_game_service_ui, 'achievements'),
)
else:
logging.warning('show_online_score_ui requires classic')
logging.warning('show_game_service_ui requires plus feature-set.')
def _on_achievements_press(self) -> None:
# pylint: disable=cyclic-import
@ -1162,11 +1287,21 @@ class AccountSettingsWindow(bui.Window):
show_what_is_v2_page()
def _on_manage_account_press(self) -> None:
bui.screenmessage(bui.Lstr(resource='oneMomentText'))
plus = bui.app.plus
assert plus is not None
# Preemptively fail if it looks like we won't be able to talk to
# the server anyway.
if not plus.cloud.connected:
bui.screenmessage(
bui.Lstr(resource='internal.unavailableNoConnectionText'),
color=(1, 0, 0),
)
bui.getsound('error').play()
return
bui.screenmessage(bui.Lstr(resource='oneMomentText'))
# We expect to have a v2 account signed in if we get here.
if plus.accounts.primary is None:
logging.exception(
@ -1184,6 +1319,9 @@ class AccountSettingsWindow(bui.Window):
self, response: bacommon.cloud.ManageAccountResponse | Exception
) -> None:
if isinstance(response, Exception) or response.url is None:
logging.warning(
'Got error in manage-account-response: %s.', response
)
bui.screenmessage(bui.Lstr(resource='errorText'), color=(1, 0, 0))
bui.getsound('error').play()
return
@ -1191,13 +1329,13 @@ class AccountSettingsWindow(bui.Window):
bui.open_url(response.url)
def _on_leaderboards_press(self) -> None:
if bui.app.classic is not None:
if bui.app.plus is not None:
bui.apptimer(
0.15,
bui.Call(bui.app.classic.show_online_score_ui, 'leaderboards'),
bui.Call(bui.app.plus.show_game_service_ui, 'leaderboards'),
)
else:
logging.warning('show_online_score_ui requires classic')
logging.warning('show_game_service_ui requires classic')
def _have_unlinkable_v1_accounts(self) -> bool:
plus = bui.app.plus
@ -1323,7 +1461,7 @@ class AccountSettingsWindow(bui.Window):
swidth = bui.get_string_width(name_str, suppress_warning=True)
# Eww; number-fudging. Need to recalibrate this if
# account name scaling changes.
x = self._sub_width * 0.5 - swidth * 0.75 - 170
x = self._sub_width * 0.5 - swidth * 0.75 - 190
bui.textwidget(
edit=self._account_name_what_is_text,
@ -1371,9 +1509,18 @@ class AccountSettingsWindow(bui.Window):
# pylint: disable=cyclic-import
from bauiv1lib.profile.browser import ProfileBrowserWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left')
ProfileBrowserWindow(origin_widget=self._player_profiles_button)
bui.app.ui_v1.set_main_menu_window(
ProfileBrowserWindow(
origin_widget=self._player_profiles_button
).get_root_widget(),
from_window=self._root_widget,
)
def _cancel_sign_in_press(self) -> None:
# If we're waiting on an adapter to give us credentials, abort.
@ -1466,7 +1613,11 @@ class AccountSettingsWindow(bui.Window):
if isinstance(result, Exception):
# For now just make a bit of noise if anything went wrong;
# can get more specific as needed later.
bui.screenmessage(bui.Lstr(resource='errorText'), color=(1, 0, 0))
logging.warning('Got error in v2 sign-in result: %s', result)
bui.screenmessage(
bui.Lstr(resource='internal.signInNoConnectionText'),
color=(1, 0, 0),
)
bui.getsound('error').play()
else:
# Success! Plug in these credentials which will begin
@ -1530,6 +1681,10 @@ class AccountSettingsWindow(bui.Window):
# pylint: disable=cyclic-import
from bauiv1lib.mainmenu import MainMenuWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(
edit=self._root_widget, transition=self._transition_out
@ -1538,7 +1693,8 @@ class AccountSettingsWindow(bui.Window):
if not self._modal:
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
MainMenuWindow(transition='in_left').get_root_widget()
MainMenuWindow(transition='in_left').get_root_widget(),
from_window=self._root_widget,
)
def _save_state(self) -> None:

View file

@ -62,11 +62,8 @@ class V2ProxySignInWindow(bui.Window):
label=bui.Lstr(resource='cancelText'),
on_activate_call=self._done,
autoselect=True,
color=(0.55, 0.5, 0.6),
textcolor=(0.75, 0.7, 0.8),
)
if bool(False):
bui.containerwidget(
edit=self._root_widget, cancel_button=self._cancel_button
)
@ -131,14 +128,17 @@ class V2ProxySignInWindow(bui.Window):
else:
bui.textwidget(
parent=self._root_widget,
position=(self._width * 0.5, self._height - 145),
size=(0, 0),
position=(self._width * 0.5 - 200, self._height - 180),
size=(button_width - 50, 50),
text=bui.Lstr(value=address_pretty),
flatness=1.0,
maxwidth=self._width,
scale=0.75,
h_align='center',
v_align='center',
autoselect=True,
on_activate_call=bui.Call(self._copy_link, address_pretty),
selectable=True,
)
qroffs = 20.0
@ -231,5 +231,15 @@ class V2ProxySignInWindow(bui.Window):
# We could do something smart like retry on exceptions here, but
# this isn't critical so we'll just let anything slide.
def _copy_link(self, link: str) -> None:
if bui.clipboard_is_supported():
bui.clipboard_set_text(link)
bui.screenmessage(
bui.Lstr(resource='copyConfirmText'), color=(0, 1, 0)
)
def _done(self) -> None:
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
bui.containerwidget(edit=self._root_widget, transition='out_scale')

View file

@ -93,6 +93,7 @@ class ConfigNumberEdit:
displayname: str | bui.Lstr | None = None,
changesound: bool = True,
textscale: float = 1.0,
as_percent: bool = False,
):
if displayname is None:
displayname = configkey
@ -103,6 +104,7 @@ class ConfigNumberEdit:
self._increment = increment
self._callback = callback
self._value = bui.app.config.resolve(configkey)
self._as_percent = as_percent
self.nametext = bui.textwidget(
parent=parent,
@ -166,4 +168,8 @@ class ConfigNumberEdit:
bui.app.config.apply_and_commit()
def _update_display(self) -> None:
bui.textwidget(edit=self.valuetext, text=f'{self._value:.1f}')
if self._as_percent:
val = f'{round(self._value*100.0)}%'
else:
val = f'{self._value:.1f}'
bui.textwidget(edit=self.valuetext, text=val)

View file

@ -153,15 +153,15 @@ class QuitWindow:
def __init__(
self,
quit_type: bui.QuitType | None = None,
swish: bool = False,
back: bool = False,
origin_widget: bui.Widget | None = None,
):
classic = bui.app.classic
assert classic is not None
ui = bui.app.ui_v1
app = bui.app
self._back = back
self._quit_type = quit_type
# If there's already one of us up somewhere, kill it.
if ui.quit_window is not None:
@ -187,29 +187,8 @@ class QuitWindow:
resource=quit_resource,
subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
),
self._fade_and_quit,
lambda: bui.quit(confirm=False, quit_type=self._quit_type)
if self._quit_type is not None
else bui.quit(confirm=False),
origin_widget=origin_widget,
).root_widget
def _fade_and_quit(self) -> None:
bui.fade_screen(
False,
time=0.2,
endcall=lambda: bui.quit(soft=True, back=self._back),
)
# Prevent the user from doing anything else while we're on our
# way out.
bui.lock_all_input()
# On systems supporting soft-quit, unlock and fade back in shortly
# (soft-quit basically just backgrounds/hides the app).
if bui.app.env.supports_soft_quit:
# Unlock and fade back in shortly. Just in case something goes
# wrong (or on Android where quit just backs out of our activity
# and we may come back after).
def _come_back() -> None:
bui.unlock_all_input()
bui.fade_screen(True)
bui.apptimer(0.5, _come_back)

View file

@ -85,8 +85,8 @@ class CoopBrowserWindow(bui.Window):
assert bui.app.classic is not None
uiscale = bui.app.ui_v1.uiscale
self._width = 1320 if uiscale is bui.UIScale.SMALL else 1120
self._x_inset = x_inset = 100 if uiscale is bui.UIScale.SMALL else 0
self._width = 1520 if uiscale is bui.UIScale.SMALL else 1120
self._x_inset = x_inset = 200 if uiscale is bui.UIScale.SMALL else 0
self._height = (
657
if uiscale is bui.UIScale.SMALL
@ -415,7 +415,7 @@ class CoopBrowserWindow(bui.Window):
)
# Decrement time on our tournament buttons.
ads_enabled = bui.have_incentivized_ad()
ads_enabled = plus.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:
@ -430,7 +430,7 @@ class CoopBrowserWindow(bui.Window):
)
# Also adjust the ad icon visibility.
if tbtn.allow_ads and bui.has_video_ads():
if tbtn.allow_ads and plus.has_video_ads():
bui.imagewidget(
edit=tbtn.entry_fee_ad_image,
opacity=1.0 if ads_enabled else 0.25,
@ -1019,6 +1019,10 @@ class CoopBrowserWindow(bui.Window):
from bauiv1lib.account import show_sign_in_prompt
from bauiv1lib.league.rankwindow import LeagueRankWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
plus = bui.app.plus
assert plus is not None
@ -1032,7 +1036,8 @@ class CoopBrowserWindow(bui.Window):
bui.app.ui_v1.set_main_menu_window(
LeagueRankWindow(
origin_widget=self._league_rank_button.get_button()
).get_root_widget()
).get_root_widget(),
from_window=self._root_widget,
)
def _switch_to_score(
@ -1043,6 +1048,10 @@ class CoopBrowserWindow(bui.Window):
# pylint: disable=cyclic-import
from bauiv1lib.account import show_sign_in_prompt
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
plus = bui.app.plus
assert plus is not None
@ -1058,7 +1067,8 @@ class CoopBrowserWindow(bui.Window):
origin_widget=self._store_button.get_button(),
show_tab=show_tab,
back_location='CoopBrowserWindow',
).get_root_widget()
).get_root_widget(),
from_window=self._root_widget,
)
def is_tourney_data_up_to_date(self) -> bool:
@ -1218,6 +1228,10 @@ class CoopBrowserWindow(bui.Window):
# pylint: disable=cyclic-import
from bauiv1lib.play import PlayWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
# If something is selected, store it.
self._save_state()
bui.containerwidget(
@ -1225,7 +1239,8 @@ class CoopBrowserWindow(bui.Window):
)
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
PlayWindow(transition='in_left').get_root_widget()
PlayWindow(transition='in_left').get_root_widget(),
from_window=self._root_widget,
)
def _save_state(self) -> None:

View file

@ -638,8 +638,8 @@ class TournamentButton:
# Now, if this fee allows ads and we support video ads, show
# the 'or ad' version.
if allow_ads and bui.has_video_ads():
ads_enabled = bui.have_incentivized_ad()
if allow_ads and plus.has_video_ads():
ads_enabled = plus.have_incentivized_ad()
bui.imagewidget(
edit=self.entry_fee_ad_image,
opacity=1.0 if ads_enabled else 0.25,

View file

@ -359,10 +359,15 @@ class CreditsListWindow(bui.Window):
def _back(self) -> None:
from bauiv1lib.mainmenu import MainMenuWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
bui.containerwidget(
edit=self._root_widget, transition=self._transition_out
)
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
MainMenuWindow(transition='in_left').get_root_widget()
MainMenuWindow(transition='in_left').get_root_widget(),
from_window=self._root_widget,
)

View file

@ -379,8 +379,13 @@ class DebugWindow(bui.Window):
# pylint: disable=cyclic-import
from bauiv1lib.settings.advanced import AdvancedSettingsWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
bui.containerwidget(edit=self._root_widget, transition='out_right')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
AdvancedSettingsWindow(transition='in_left').get_root_widget()
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
from_window=self._root_widget,
)

133
dist/ba_data/python/bauiv1lib/discord.py vendored Normal file
View file

@ -0,0 +1,133 @@
# Released under the MIT License. See LICENSE for details.
#
"""UI functionality for the Discord window."""
from __future__ import annotations
import bauiv1 as bui
class DiscordWindow(bui.Window):
"""Window for joining the Discord."""
def __init__(
self,
transition: str = 'in_right',
origin_widget: bui.Widget | None = None,
):
if bui.app.classic is None:
raise RuntimeError('This requires classic support.')
app = bui.app
assert app.classic is not None
# If they provided an origin-widget, scale up from that.
scale_origin: tuple[float, float] | None
if origin_widget is not None:
self._transition_out = 'out_scale'
scale_origin = origin_widget.get_screen_space_center()
transition = 'in_scale'
else:
self._transition_out = 'out_right'
scale_origin = None
uiscale = bui.app.ui_v1.uiscale
self._width = 800
x_inset = 100 if uiscale is bui.UIScale.SMALL else 0
self._height = 320
top_extra = 10 if uiscale is bui.UIScale.SMALL else 0
super().__init__(
root_widget=bui.containerwidget(
size=(self._width, self._height + top_extra),
transition=transition,
toolbar_visibility='menu_minimal',
scale_origin_stack_offset=scale_origin,
scale=(
1.6
if uiscale is bui.UIScale.SMALL
else 1.3
if uiscale is bui.UIScale.MEDIUM
else 1.0
),
stack_offset=(0, 5) if uiscale is bui.UIScale.SMALL else (0, 0),
)
)
if app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
bui.containerwidget(
edit=self._root_widget, on_cancel_call=self._do_back
)
self._back_button = None
else:
self._back_button = bui.buttonwidget(
parent=self._root_widget,
position=(53 + x_inset, self._height - 60),
size=(140, 60),
scale=0.8,
autoselect=True,
label=bui.Lstr(resource='backText'),
button_type='back',
on_activate_call=self._do_back,
)
bui.containerwidget(
edit=self._root_widget, cancel_button=self._back_button
)
# Do we need to translate 'Discord'? Or is that always the name?
self._title_text = bui.textwidget(
parent=self._root_widget,
position=(0, self._height - 52),
size=(self._width, 25),
text='Discord',
color=app.ui_v1.title_color,
h_align='center',
v_align='top',
)
min_size = min(self._width - 25, self._height - 25)
bui.imagewidget(
parent=self._root_widget,
position=(40, -15),
size=(min_size, min_size),
texture=bui.gettexture('discordServer'),
)
# Hmm should we translate this? The discord server is mostly
# English so being able to read this might be a good screening
# process?..
bui.textwidget(
parent=self._root_widget,
position=(self._width / 2 - 60, self._height - 100),
text='We have our own Discord server where you can:\n- Find new'
' friends and people to play with\n- Participate in Office'
' Hours/Coffee with Eric\n- Share mods, plugins, art, and'
' memes\n- Report bugs and make feature suggestions\n'
'- Troubleshoot issues',
maxwidth=(self._width - 10) / 2,
color=(1, 1, 1, 1),
h_align='left',
v_align='top',
)
bui.buttonwidget(
parent=self._root_widget,
position=(self._width / 2 - 30, 20),
size=(self._width / 2 - 60, 60),
autoselect=True,
label=bui.Lstr(resource='discordJoinText'),
text_scale=1.0,
on_activate_call=bui.Call(
bui.open_url, 'https://ballistica.net/discord'
),
)
if self._back_button is not None:
bui.buttonwidget(
edit=self._back_button,
button_type='backSmall',
size=(60, 60),
label=bui.charstr(bui.SpecialChar.BACK),
)
def _do_back(self) -> None:
bui.containerwidget(edit=self._root_widget, transition='out_scale')

View file

@ -94,8 +94,8 @@ class GatherWindow(bui.Window):
bui.app.ui_v1.set_main_menu_location('Gather')
bui.set_party_icon_always_visible(True)
uiscale = bui.app.ui_v1.uiscale
self._width = 1240 if uiscale is bui.UIScale.SMALL else 1040
x_offs = 100 if uiscale is bui.UIScale.SMALL else 0
self._width = 1440 if uiscale is bui.UIScale.SMALL else 1040
x_offs = 200 if uiscale is bui.UIScale.SMALL else 0
self._height = (
582
if uiscale is bui.UIScale.SMALL
@ -270,12 +270,17 @@ class GatherWindow(bui.Window):
"""Called by the private-hosting tab to select a playlist."""
from bauiv1lib.play import PlayWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.selecting_private_party_playlist = True
bui.app.ui_v1.set_main_menu_window(
PlayWindow(origin_widget=origin_widget).get_root_widget()
PlayWindow(origin_widget=origin_widget).get_root_widget(),
from_window=self._root_widget,
)
def _set_tab(self, tab_id: TabID) -> None:
@ -383,11 +388,16 @@ class GatherWindow(bui.Window):
def _back(self) -> None:
from bauiv1lib.mainmenu import MainMenuWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(
edit=self._root_widget, transition=self._transition_out
)
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
MainMenuWindow(transition='in_left').get_root_widget()
MainMenuWindow(transition='in_left').get_root_widget(),
from_window=self._root_widget,
)

View file

@ -16,10 +16,6 @@ if TYPE_CHECKING:
class AboutGatherTab(GatherTab):
"""The about tab in the gather UI"""
def __init__(self, window: GatherWindow) -> None:
super().__init__(window)
self._container: bui.Widget | None = None
def on_activate(
self,
parent_widget: bui.Widget,
@ -29,9 +25,45 @@ class AboutGatherTab(GatherTab):
region_left: float,
region_bottom: float,
) -> bui.Widget:
# pylint: disable=too-many-locals
plus = bui.app.plus
assert plus is not None
try_tickets = plus.get_v1_account_misc_read_val(
'friendTryTickets', None
)
show_message = True
# Squish message as needed to get things to fit nicely at
# various scales.
uiscale = bui.app.ui_v1.uiscale
message_height = (
210
if uiscale is bui.UIScale.SMALL
else 305
if uiscale is bui.UIScale.MEDIUM
else 370
)
# Let's not talk about sharing in vr-mode; its tricky to fit more
# than one head in a VR-headset.
show_message_extra = not bui.app.env.vr
message_extra_height = 60
show_invite = try_tickets is not None
invite_height = 80
show_discord = True
discord_height = 80
c_height = 0
if show_message:
c_height += message_height
if show_message_extra:
c_height += message_extra_height
if show_invite:
c_height += invite_height
if show_discord:
c_height += discord_height
party_button_label = bui.charstr(bui.SpecialChar.TOP_BUTTON)
message = bui.Lstr(
resource='gatherWindow.aboutDescriptionText',
@ -41,9 +73,7 @@ class AboutGatherTab(GatherTab):
],
)
# Let's not talk about sharing in vr-mode; its tricky to fit more
# than one head in a VR-headset ;-)
if not bui.app.env.vr:
if show_message_extra:
message = bui.Lstr(
value='${A}\n\n${B}',
subs=[
@ -57,47 +87,52 @@ class AboutGatherTab(GatherTab):
),
],
)
string_height = 400
include_invite = True
msc_scale = 1.1
c_height_2 = min(region_height, string_height * msc_scale + 100)
try_tickets = plus.get_v1_account_misc_read_val(
'friendTryTickets', None
)
if try_tickets is None:
include_invite = False
self._container = bui.containerwidget(
scroll_widget = bui.scrollwidget(
parent=parent_widget,
position=(region_left, region_bottom),
size=(region_width, region_height),
highlight=False,
border_opacity=0,
)
msc_scale = 1.1
container = bui.containerwidget(
parent=scroll_widget,
position=(
region_left,
region_bottom + (region_height - c_height_2) * 0.5,
region_bottom + (region_height - c_height) * 0.5,
),
size=(region_width, c_height_2),
size=(region_width, c_height),
background=False,
selectable=include_invite,
selectable=show_invite or show_discord,
)
bui.widget(edit=self._container, up_widget=tab_button)
# Allows escaping if we select the container somehow (though
# shouldn't be possible when buttons are present).
bui.widget(edit=container, up_widget=tab_button)
y = c_height - 30
if show_message:
bui.textwidget(
parent=self._container,
position=(
region_width * 0.5,
c_height_2 * (0.58 if include_invite else 0.5),
),
parent=container,
position=(region_width * 0.5, y),
color=(0.6, 1.0, 0.6),
scale=msc_scale,
size=(0, 0),
maxwidth=region_width * 0.9,
max_height=c_height_2 * (0.7 if include_invite else 0.9),
max_height=message_height,
h_align='center',
v_align='center',
v_align='top',
text=message,
)
y -= message_height
if show_message_extra:
y -= message_extra_height
if include_invite:
if show_invite:
bui.textwidget(
parent=self._container,
position=(region_width * 0.57, 35),
parent=container,
position=(region_width * 0.57, y),
color=(0, 1, 0),
scale=0.6,
size=(0, 0),
@ -110,9 +145,9 @@ class AboutGatherTab(GatherTab):
subs=[('${COUNT}', str(try_tickets))],
),
)
bui.buttonwidget(
parent=self._container,
position=(region_width * 0.59, 10),
invite_button = bui.buttonwidget(
parent=container,
position=(region_width * 0.59, y - 25),
size=(230, 50),
color=(0.54, 0.42, 0.56),
textcolor=(0, 1, 0),
@ -124,7 +159,44 @@ class AboutGatherTab(GatherTab):
on_activate_call=bui.WeakCall(self._invite_to_try_press),
up_widget=tab_button,
)
return self._container
y -= invite_height
else:
invite_button = None
if show_discord:
bui.textwidget(
parent=container,
position=(region_width * 0.57, y),
color=(0.6, 0.6, 1),
scale=0.6,
size=(0, 0),
maxwidth=region_width * 0.5,
h_align='right',
v_align='center',
flatness=1.0,
text=bui.Lstr(resource='discordFriendsText'),
)
discord_button = bui.buttonwidget(
parent=container,
position=(region_width * 0.59, y - 25),
size=(230, 50),
color=(0.54, 0.42, 0.56),
textcolor=(0.6, 0.6, 1),
label=bui.Lstr(resource='discordJoinText'),
autoselect=True,
on_activate_call=bui.WeakCall(self._join_the_discord_press),
up_widget=(
invite_button if invite_button is not None else tab_button
),
)
y -= discord_height
else:
discord_button = None
if discord_button is not None:
pass
return scroll_widget
def _invite_to_try_press(self) -> None:
from bauiv1lib.account import show_sign_in_prompt
@ -137,3 +209,10 @@ class AboutGatherTab(GatherTab):
show_sign_in_prompt()
return
handle_app_invites_press()
def _join_the_discord_press(self) -> None:
# pylint: disable=cyclic-import
from bauiv1lib.discord import DiscordWindow
assert bui.app.classic is not None
DiscordWindow().get_root_widget()

View file

@ -99,6 +99,7 @@ class ManualGatherTab(GatherTab):
self._party_edit_name_text: bui.Widget | None = None
self._party_edit_addr_text: bui.Widget | None = None
self._party_edit_port_text: bui.Widget | None = None
self._no_parties_added_text: bui.Widget | None = None
def on_activate(
self,
@ -142,6 +143,7 @@ class ManualGatherTab(GatherTab):
playsound=True,
),
text=bui.Lstr(resource='gatherWindow.manualJoinSectionText'),
glow_type='uniform',
)
self._favorites_text = bui.textwidget(
parent=self._container,
@ -162,6 +164,7 @@ class ManualGatherTab(GatherTab):
playsound=True,
),
text=bui.Lstr(resource='gatherWindow.favoritesText'),
glow_type='uniform',
)
bui.widget(edit=self._join_by_address_text, up_widget=tab_button)
bui.widget(
@ -316,7 +319,7 @@ class ManualGatherTab(GatherTab):
self._check_button = bui.textwidget(
parent=self._container,
size=(250, 60),
text=bui.Lstr(resource='gatherWindow.' 'showMyAddressText'),
text=bui.Lstr(resource='gatherWindow.showMyAddressText'),
v_align='center',
h_align='center',
click_activate=True,
@ -331,6 +334,7 @@ class ManualGatherTab(GatherTab):
self._container,
c_width,
),
glow_type='uniform',
)
bui.widget(edit=self._check_button, up_widget=btn)
@ -453,6 +457,24 @@ class ManualGatherTab(GatherTab):
claims_left_right=True,
)
self._no_parties_added_text = bui.textwidget(
parent=self._container,
size=(0, 0),
h_align='center',
v_align='center',
text='',
color=(0.6, 0.6, 0.6),
scale=1.2,
position=(
(
(190 if uiscale is bui.UIScale.SMALL else 225)
+ sub_scroll_width * 0.5
),
v + sub_scroll_height * 0.5,
),
glow_type='uniform',
)
self._favorite_selected = None
self._refresh_favorites()
@ -695,6 +717,12 @@ class ManualGatherTab(GatherTab):
assert self._favorites_scroll_width is not None
assert self._favorites_connect_button is not None
bui.textwidget(
edit=self._no_parties_added_text,
text='',
)
num_of_fav = 0
for i, server in enumerate(servers):
txt = bui.textwidget(
parent=self._columnwidget,
@ -718,11 +746,13 @@ class ManualGatherTab(GatherTab):
)
if i == 0:
bui.widget(edit=txt, up_widget=self._favorites_text)
self._favorite_selected = server
bui.widget(
edit=txt,
left_widget=self._favorites_connect_button,
right_widget=txt,
)
num_of_fav = num_of_fav + 1
# If there's no servers, allow selecting out of the scroll area
bui.containerwidget(
@ -735,6 +765,11 @@ class ManualGatherTab(GatherTab):
up_widget=self._favorites_text,
left_widget=self._favorites_connect_button,
)
if num_of_fav == 0:
bui.textwidget(
edit=self._no_parties_added_text,
text=bui.Lstr(resource='gatherWindow.noPartiesAddedText'),
)
def on_deactivate(self) -> None:
self._access_check_timer = None
@ -800,8 +835,17 @@ class ManualGatherTab(GatherTab):
}
config.commit()
bui.getsound('gunCocking').play()
bui.screenmessage(
bui.Lstr(
resource='addedToFavoritesText', subs=[('${NAME}', addr)]
),
color=(0, 1, 0),
)
else:
bui.screenmessage('Invalid Address', color=(1, 0, 0))
bui.screenmessage(
bui.Lstr(resource='internal.invalidAddressErrorText'),
color=(1, 0, 0),
)
bui.getsound('error').play()
def _host_lookup_result(

View file

@ -120,6 +120,7 @@ class PrivateGatherTab(GatherTab):
playsound=True,
),
text=bui.Lstr(resource='gatherWindow.privatePartyJoinText'),
glow_type='uniform',
)
self._host_sub_tab_text = bui.textwidget(
parent=self._container,
@ -138,6 +139,7 @@ class PrivateGatherTab(GatherTab):
playsound=True,
),
text=bui.Lstr(resource='gatherWindow.privatePartyHostText'),
glow_type='uniform',
)
bui.widget(edit=self._join_sub_tab_text, up_widget=tab_button)
bui.widget(
@ -458,9 +460,9 @@ class PrivateGatherTab(GatherTab):
scale=1.5,
size=(300, 50),
editable=True,
max_chars=20,
description=bui.Lstr(resource='gatherWindow.partyCodeText'),
autoselect=True,
maxwidth=250,
h_align='left',
v_align='center',
text='',
@ -962,7 +964,7 @@ class PrivateGatherTab(GatherTab):
code = cast(str, bui.textwidget(query=self._join_party_code_text))
if not code:
bui.screenmessage(
bui.Lstr(resource='internal.invalidAddressErrorText'),
bui.Lstr(translate=('serverResponses', 'Invalid code.')),
color=(1, 0, 0),
)
bui.getsound('error').play()

View file

@ -114,7 +114,7 @@ class UIRow:
self._name_widget = bui.textwidget(
text=bui.Lstr(value=party.name),
parent=columnwidget,
size=(sub_scroll_width * 0.63, 20),
size=(sub_scroll_width * 0.46, 20),
position=(0 + hpos, 4 + vpos),
selectable=True,
on_select_call=bui.WeakCall(
@ -248,6 +248,7 @@ class AddrFetchThread(Thread):
self._call = call
def run(self) -> None:
sock: socket.socket | None = None
try:
# FIXME: Update this to work with IPv6 at some point.
import socket
@ -255,7 +256,6 @@ class AddrFetchThread(Thread):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.connect(('8.8.8.8', 80))
val = sock.getsockname()[0]
sock.close()
bui.pushcall(bui.Call(self._call, val), from_other_thread=True)
except Exception as exc:
from efro.error import is_udp_communication_error
@ -265,6 +265,9 @@ class AddrFetchThread(Thread):
pass
else:
logging.exception('Error in addr-fetch-thread')
finally:
if sock is not None:
sock.close()
class PingThread(Thread):
@ -361,6 +364,7 @@ class PublicGatherTab(GatherTab):
self._last_server_list_query_time: float | None = None
self._join_list_column: bui.Widget | None = None
self._join_status_text: bui.Widget | None = None
self._no_servers_found_text: bui.Widget | None = None
self._host_max_party_size_value: bui.Widget | None = None
self._host_max_party_size_minus_button: (bui.Widget | None) = None
self._host_max_party_size_plus_button: (bui.Widget | None) = None
@ -431,6 +435,7 @@ class PublicGatherTab(GatherTab):
text=bui.Lstr(
resource='gatherWindow.' 'joinPublicPartyDescriptionText'
),
glow_type='uniform',
)
self._host_text = bui.textwidget(
parent=self._container,
@ -453,6 +458,7 @@ class PublicGatherTab(GatherTab):
text=bui.Lstr(
resource='gatherWindow.' 'hostPublicPartyDescriptionText'
),
glow_type='uniform',
)
bui.widget(edit=self._join_text, up_widget=tab_button)
bui.widget(
@ -658,6 +664,18 @@ class PublicGatherTab(GatherTab):
color=(0.6, 0.6, 0.6),
position=(c_width * 0.5, c_height * 0.5),
)
self._no_servers_found_text = bui.textwidget(
parent=self._container,
text='',
size=(0, 0),
scale=0.9,
flatness=1.0,
shadow=0.0,
h_align='center',
v_align='top',
color=(0.6, 0.6, 0.6),
position=(c_width * 0.5, c_height * 0.5),
)
def _build_host_tab(
self, region_width: float, region_height: float
@ -950,6 +968,9 @@ class PublicGatherTab(GatherTab):
self._update_party_rows()
def _update_party_rows(self) -> None:
plus = bui.app.plus
assert plus is not None
columnwidget = self._join_list_column
if not columnwidget:
return
@ -963,6 +984,7 @@ class PublicGatherTab(GatherTab):
edit=self._host_scrollwidget,
claims_up_down=(len(self._parties_displayed) > 0),
)
bui.textwidget(edit=self._no_servers_found_text, text='')
# Clip if we have more UI rows than parties to show.
clipcount = len(self._ui_rows) - len(self._parties_displayed)
@ -972,6 +994,15 @@ class PublicGatherTab(GatherTab):
# If we have no parties to show, we're done.
if not self._parties_displayed:
text = self._join_status_text
if (
plus.get_v1_account_state() == 'signed_in'
and cast(str, bui.textwidget(query=text)) == ''
):
bui.textwidget(
edit=self._no_servers_found_text,
text=bui.Lstr(resource='noServersFoundText'),
)
return
sub_scroll_width = 830

View file

@ -334,7 +334,7 @@ class GetCurrencyWindow(bui.Window):
tex_scale=1.2,
) # 19.99-ish
self._enable_ad_button = bui.has_video_ads()
self._enable_ad_button = plus.has_video_ads()
h = self._width * 0.5 + 110.0
v = self._height - b_size[1] - 115.0
@ -561,7 +561,7 @@ class GetCurrencyWindow(bui.Window):
next_reward_ad_time
)
now = datetime.datetime.utcnow()
if bui.have_incentivized_ad() and (
if plus.have_incentivized_ad() and (
next_reward_ad_time is None or next_reward_ad_time <= now
):
self._ad_button_greyed = False
@ -732,8 +732,13 @@ class GetCurrencyWindow(bui.Window):
def _back(self) -> None:
from bauiv1lib.store import browser
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
if self._transitioning_out:
return
bui.containerwidget(
edit=self._root_widget, transition=self._transition_out
)
@ -745,7 +750,9 @@ class GetCurrencyWindow(bui.Window):
).get_root_widget()
if not self._from_modal_store:
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(window)
bui.app.ui_v1.set_main_menu_window(
window, from_window=self._root_widget
)
self._transitioning_out = True

View file

@ -36,8 +36,8 @@ class HelpWindow(bui.Window):
self._main_menu = main_menu
assert bui.app.classic is not None
uiscale = bui.app.ui_v1.uiscale
width = 950 if uiscale is bui.UIScale.SMALL else 750
x_offs = 100 if uiscale is bui.UIScale.SMALL else 0
width = 1050 if uiscale is bui.UIScale.SMALL else 750
x_offs = 150 if uiscale is bui.UIScale.SMALL else 0
height = (
460
if uiscale is bui.UIScale.SMALL
@ -645,11 +645,16 @@ class HelpWindow(bui.Window):
# pylint: disable=cyclic-import
from bauiv1lib.mainmenu import MainMenuWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
bui.containerwidget(
edit=self._root_widget, transition=self._transition_out
)
if self._main_menu:
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
MainMenuWindow(transition='in_left').get_root_widget()
MainMenuWindow(transition='in_left').get_root_widget(),
from_window=self._root_widget,
)

View file

@ -9,7 +9,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import bauiv1 as bui
if TYPE_CHECKING:
from typing import Iterable
@ -33,15 +33,15 @@ def split(chars: Iterable[str], maxlen: int) -> list[list[str]]:
def generate_emojis(maxlen: int) -> list[list[str]]:
"""Generates a lot of UTF8 emojis prepared for babase.Keyboard pages"""
"""Generates a lot of UTF8 emojis prepared for bui.Keyboard pages"""
all_emojis = split([chr(i) for i in range(0x1F601, 0x1F650)], maxlen)
all_emojis += split([chr(i) for i in range(0x2702, 0x27B1)], maxlen)
all_emojis += split([chr(i) for i in range(0x1F680, 0x1F6C1)], maxlen)
return all_emojis
# ba_meta export keyboard
class EnglishKeyboard(babase.Keyboard):
# ba_meta export bauiv1.Keyboard
class EnglishKeyboard(bui.Keyboard):
"""Default English keyboard."""
name = 'English'

View file

@ -21,7 +21,7 @@ class KioskWindow(bui.Window):
self._height = 340.0
def _do_cancel() -> None:
QuitWindow(swish=True, back=True)
QuitWindow(swish=True, quit_type=bui.QuitType.BACK)
super().__init__(
root_widget=bui.containerwidget(
@ -501,9 +501,15 @@ class KioskWindow(bui.Window):
def _do_full_menu(self) -> None:
from bauiv1lib.mainmenu import MainMenuWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
assert bui.app.classic is not None
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left')
bui.app.classic.did_menu_intro = True # prevent delayed transition-in
bui.app.ui_v1.set_main_menu_window(MainMenuWindow().get_root_widget())
bui.app.ui_v1.set_main_menu_window(
MainMenuWindow().get_root_widget(), from_window=self._root_widget
)

View file

@ -1142,6 +1142,10 @@ class LeagueRankWindow(bui.Window):
def _back(self) -> None:
from bauiv1lib.coop.browser import CoopBrowserWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(
edit=self._root_widget, transition=self._transition_out
@ -1149,5 +1153,6 @@ class LeagueRankWindow(bui.Window):
if not self._modal:
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
CoopBrowserWindow(transition='in_left').get_root_widget()
CoopBrowserWindow(transition='in_left').get_root_widget(),
from_window=self._root_widget,
)

View file

@ -190,7 +190,6 @@ class MainMenuWindow(bui.Window):
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
# pylint: disable=too-many-statements
from bauiv1lib.confirm import QuitWindow
from bauiv1lib.store.button import StoreButton
plus = bui.app.plus
@ -312,8 +311,8 @@ class MainMenuWindow(bui.Window):
else self._confirm_end_game
),
)
# Assume we're in a client-session.
else:
# Assume we're in a client-session.
bui.buttonwidget(
parent=self._root_widget,
position=(h - self._button_width * 0.5 * scale, v),
@ -361,7 +360,6 @@ class MainMenuWindow(bui.Window):
tilt_scale=0.0,
draw_controller=store_button,
)
self._tdelay += self._t_delay_inc
else:
self._store_button = None
@ -422,7 +420,7 @@ class MainMenuWindow(bui.Window):
):
def _do_quit() -> None:
QuitWindow(swish=True, back=True)
bui.quit(confirm=True, quit_type=bui.QuitType.BACK)
bui.containerwidget(
edit=self._root_widget, on_cancel_call=_do_quit
@ -1040,30 +1038,47 @@ class MainMenuWindow(bui.Window):
# pylint: disable=cyclic-import
from bauiv1lib.confirm import QuitWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
# Note: Normally we should go through bui.quit(confirm=True) but
# invoking the window directly lets us scale it up from the
# button.
QuitWindow(origin_widget=self._quit_button)
def _demo_menu_press(self) -> None:
# pylint: disable=cyclic-import
from bauiv1lib.kiosk import KioskWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_right')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
KioskWindow(transition='in_left').get_root_widget()
KioskWindow(transition='in_left').get_root_widget(),
from_window=self._root_widget,
)
def _show_account_window(self) -> None:
# pylint: disable=cyclic-import
from bauiv1lib.account.settings import AccountSettingsWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
AccountSettingsWindow(
origin_widget=self._account_button
).get_root_widget()
).get_root_widget(),
from_window=self._root_widget,
)
def _on_store_pressed(self) -> None:
@ -1071,6 +1086,10 @@ class MainMenuWindow(bui.Window):
from bauiv1lib.store.browser import StoreBrowserWindow
from bauiv1lib.account import show_sign_in_prompt
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
plus = bui.app.plus
assert plus is not None
@ -1083,7 +1102,8 @@ class MainMenuWindow(bui.Window):
bui.app.ui_v1.set_main_menu_window(
StoreBrowserWindow(
origin_widget=self._store_button
).get_root_widget()
).get_root_widget(),
from_window=self._root_widget,
)
def _is_benchmark(self) -> bool:
@ -1148,8 +1168,11 @@ class MainMenuWindow(bui.Window):
def _end_game(self) -> None:
assert bui.app.classic is not None
if not self._root_widget:
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
bui.containerwidget(edit=self._root_widget, transition='out_left')
bui.app.classic.return_to_main_menu_session_gracefully(reset_ui=False)
@ -1165,39 +1188,54 @@ class MainMenuWindow(bui.Window):
# pylint: disable=cyclic-import
from bauiv1lib.creditslist import CreditsListWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
CreditsListWindow(
origin_widget=self._credits_button
).get_root_widget()
).get_root_widget(),
from_window=self._root_widget,
)
def _howtoplay(self) -> None:
# pylint: disable=cyclic-import
from bauiv1lib.helpui import HelpWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
HelpWindow(
main_menu=True, origin_widget=self._how_to_play_button
).get_root_widget()
).get_root_widget(),
from_window=self._root_widget,
)
def _settings(self) -> None:
# pylint: disable=cyclic-import
from bauiv1lib.settings.allsettings import AllSettingsWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
AllSettingsWindow(
origin_widget=self._settings_button
).get_root_widget()
).get_root_widget(),
from_window=self._root_widget,
)
def _resume_and_call(self, call: Callable[[], Any]) -> None:
@ -1206,10 +1244,12 @@ class MainMenuWindow(bui.Window):
def _do_game_service_press(self) -> None:
self._save_state()
if bui.app.classic is not None:
bui.app.classic.show_online_score_ui()
if bui.app.plus is not None:
bui.app.plus.show_game_service_ui()
else:
logging.warning('classic is required to show game service ui')
logging.warning(
'plus feature-set is required to show game service ui'
)
def _save_state(self) -> None:
# Don't do this for the in-game menu.
@ -1280,35 +1320,50 @@ class MainMenuWindow(bui.Window):
# pylint: disable=cyclic-import
from bauiv1lib.gather import GatherWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
GatherWindow(origin_widget=self._gather_button).get_root_widget()
GatherWindow(origin_widget=self._gather_button).get_root_widget(),
from_window=self._root_widget,
)
def _watch_press(self) -> None:
# pylint: disable=cyclic-import
from bauiv1lib.watch import WatchWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_menu_window(
WatchWindow(origin_widget=self._watch_button).get_root_widget()
WatchWindow(origin_widget=self._watch_button).get_root_widget(),
from_window=self._root_widget,
)
def _play_press(self) -> None:
# pylint: disable=cyclic-import
from bauiv1lib.play import PlayWindow
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.selecting_private_party_playlist = False
bui.app.ui_v1.set_main_menu_window(
PlayWindow(origin_widget=self._start_button).get_root_widget()
PlayWindow(origin_widget=self._start_button).get_root_widget(),
from_window=self._root_widget,
)
def _resume(self) -> None:
@ -1316,7 +1371,7 @@ class MainMenuWindow(bui.Window):
bui.app.classic.resume()
if self._root_widget:
bui.containerwidget(edit=self._root_widget, transition='out_right')
bui.app.ui_v1.clear_main_menu_window()
bui.app.ui_v1.clear_main_menu_window(transition='out_right')
# If there's callbacks waiting for this window to go away, call them.
for call in bui.app.ui_v1.main_menu_resume_callbacks:

View file

@ -40,6 +40,7 @@ class PartyWindow(bui.Window):
if uiscale is bui.UIScale.MEDIUM
else 600
)
self._display_old_msgs = True
super().__init__(
root_widget=bui.containerwidget(
size=(self._width, self._height),
@ -92,9 +93,10 @@ class PartyWindow(bui.Window):
iconscale=1.2,
)
info = bs.get_connection_to_host_info()
if info.get('name', '') != '':
title = bui.Lstr(value=info['name'])
info = bs.get_connection_to_host_info_2()
if info is not None and info.name != '':
title = bui.Lstr(value=info.name)
else:
title = bui.Lstr(resource=self._r + '.titleText')
@ -142,12 +144,6 @@ class PartyWindow(bui.Window):
)
self._chat_texts: list[bui.Widget] = []
# add all existing messages if chat is not muted
if not bui.app.config.resolve('Chat Muted'):
msgs = bs.get_chat_messages()
for msg in msgs:
self._add_msg(msg)
self._text_field = txt = bui.textwidget(
parent=self._root_widget,
editable=True,
@ -233,6 +229,23 @@ class PartyWindow(bui.Window):
is_muted = bui.app.config.resolve('Chat Muted')
assert bui.app.classic is not None
uiscale = bui.app.ui_v1.uiscale
choices: list[str] = ['unmute' if is_muted else 'mute']
choices_display: list[bui.Lstr] = [
bui.Lstr(resource='chatUnMuteText' if is_muted else 'chatMuteText')
]
# Allow the 'Add to Favorites' option only if we're actually
# connected to a party and if it doesn't seem to be a private
# party (those are dynamically assigned addresses and ports so
# it makes no sense to save them).
server_info = bs.get_connection_to_host_info_2()
if server_info is not None and not server_info.name.startswith(
'Private Party '
):
choices.append('add_to_favorites')
choices_display.append(bui.Lstr(resource='addToFavoritesText'))
PopupMenuWindow(
position=self._menu_button.get_screen_space_center(),
scale=(
@ -242,12 +255,8 @@ class PartyWindow(bui.Window):
if uiscale is bui.UIScale.MEDIUM
else 1.23
),
choices=['unmute' if is_muted else 'mute'],
choices_display=[
bui.Lstr(
resource='chatUnMuteText' if is_muted else 'chatMuteText'
)
],
choices=choices,
choices_display=choices_display,
current_choice='unmute' if is_muted else 'mute',
delegate=self,
)
@ -269,6 +278,12 @@ class PartyWindow(bui.Window):
first.delete()
else:
bui.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0))
# add all existing messages if chat is not muted
if self._display_old_msgs:
msgs = bs.get_chat_messages()
for msg in msgs:
self._add_msg(msg)
self._display_old_msgs = False
# update roster section
roster = bs.get_game_roster()
@ -466,10 +481,75 @@ class PartyWindow(bui.Window):
cfg = bui.app.config
cfg['Chat Muted'] = choice == 'mute'
cfg.apply_and_commit()
self._display_old_msgs = True
self._update()
if choice == 'add_to_favorites':
info = bs.get_connection_to_host_info_2()
if info is not None:
self._add_to_favorites(
name=info.name,
address=info.address,
port_num=info.port,
)
else:
# We should not allow the user to see this option
# if they aren't in a server; this is our bad.
bui.screenmessage(
bui.Lstr(resource='errorText'), color=(1, 0, 0)
)
bui.getsound('error').play()
else:
print(f'unhandled popup type: {self._popup_type}')
def _add_to_favorites(
self, name: str, address: str | None, port_num: int | None
) -> None:
addr = address
if addr == '':
bui.screenmessage(
bui.Lstr(resource='internal.invalidAddressErrorText'),
color=(1, 0, 0),
)
bui.getsound('error').play()
return
port = port_num if port_num is not None else -1
if port > 65535 or port < 0:
bui.screenmessage(
bui.Lstr(resource='internal.invalidPortErrorText'),
color=(1, 0, 0),
)
bui.getsound('error').play()
return
# Avoid empty names.
if not name:
name = f'{addr}@{port}'
config = bui.app.config
if addr:
if not isinstance(config.get('Saved Servers'), dict):
config['Saved Servers'] = {}
config['Saved Servers'][f'{addr}@{port}'] = {
'addr': addr,
'port': port,
'name': name,
}
config.commit()
bui.getsound('gunCocking').play()
bui.screenmessage(
bui.Lstr(
resource='addedToFavoritesText', subs=[('${NAME}', name)]
),
color=(0, 1, 0),
)
else:
bui.screenmessage(
bui.Lstr(resource='internal.invalidAddressErrorText'),
color=(1, 0, 0),
)
bui.getsound('error').play()
def popup_menu_closing(self, popup_window: PopupWindow) -> None:
"""Called when the popup is closing."""
@ -481,7 +561,8 @@ class PartyWindow(bui.Window):
kick_str = bui.Lstr(resource='kickText')
else:
# kick-votes appeared in build 14248
if bs.get_connection_to_host_info().get('build_number', 0) < 14248:
info = bs.get_connection_to_host_info_2()
if info is None or info.build_number < 14248:
return
kick_str = bui.Lstr(resource='kickVoteText')
assert bui.app.classic is not None
@ -510,9 +591,17 @@ class PartyWindow(bui.Window):
def close(self) -> None:
"""Close the window."""
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
bui.containerwidget(edit=self._root_widget, transition='out_scale')
def close_with_sound(self) -> None:
"""Close the window and make a lovely sound."""
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
bui.getsound('swish').play()
self.close()

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