mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-05 06:53:18 +08:00
Consolidated achievement functionality into AchievementSubsystem obj at ba.app.ach
This commit is contained in:
parent
2d5c2dda9a
commit
0f9fe41542
@ -3932,24 +3932,24 @@
|
|||||||
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
|
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
|
||||||
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
|
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
|
||||||
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
|
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
|
||||||
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/68/70/ecdec08c0236f5bebbf298c9f4cd",
|
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/74/73bd143107ea1bc1cc150cf1d9a0",
|
||||||
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/85/7f/53fb1e3f1414b4865315d815b17a",
|
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/1f/b71688ce17abe2f1750d3b98c1a3",
|
||||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9e/ae/586229f233660b6b49ca655b7c1b",
|
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/f5/0fb038ef5e8c9cb22f8487213622",
|
||||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e5/a5/c6b90e3629a8041a68827aafec3f",
|
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a7/22/7582b2dc2eb28e8c9b05c7860c83",
|
||||||
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d3/66/82b2cab9b1438c30cfd33eefba5e",
|
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/01/6a/6787038c5a2fe07be6dd08d6df5f",
|
||||||
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/52/37/253765404b79740cd4a7ac5fe325",
|
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/eb/c3/12a2c00732a90af63ae853b76a3b",
|
||||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c7/69/ecdbcee9df40225475391beb4cb2",
|
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/63/e7/795fd31307cda51524ea0cfc4055",
|
||||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/51/cb528ea6eb5ac853794922a0cc34",
|
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/92/48/1bfcef97e05d641771a934e312f3",
|
||||||
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d4/b8/d3a690970ca379d805432bde8533",
|
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cf/25/4ef41f30fb1380505759a16a7302",
|
||||||
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4d/16/b9014f5d983481731b54f7045dd9",
|
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/78/eb/9ee7487ac9d633020c02bcdd475b",
|
||||||
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1e/11/d3c478923937f376eecb25561ae9",
|
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4e/59/bd1e3f68c9ccf0180187dbf60ce1",
|
||||||
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d6/b4/b7854676ec826e42aa3ecb394b49",
|
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3c/f2/e0eb7217dba038dd146421b0bf5e",
|
||||||
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7a/76/bf185c1ea65f3c25cfa63666511b",
|
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/66/0f/34874cece602328e1a2b27efbe09",
|
||||||
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/49/30/5acd0d56b736a3729e7689cd4e18",
|
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ee/58/ccc75a3b2679f01a9e9b9f693ab0",
|
||||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f7/e8/197874ac6d756c341628ea4bb518",
|
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2a/82/a34db5a370d695fb52891b0a7c54",
|
||||||
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/50/6f/140a3d77288e2355605c9d0c942a",
|
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1b/c4/0b7f73a301f24177650efb8cfa69",
|
||||||
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1c/ca/62d29425e0ad0b17c145ecbc97fe",
|
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e6/55/d4819d9a2e5dcd48c2b2641c57df",
|
||||||
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c0/fa/52a38fc153714bff3bcda077ed75",
|
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/21/3f/8c9d1590314cd5172e944f64e41c",
|
||||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/75/5b/e84edb24f5df313bb6ebafa91b19",
|
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/91/72/b037555786dfb8a5ebc36467e60f",
|
||||||
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0f/2e/af28c0026c0379e5441e789e9721"
|
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e3/e1/c9e61438f6458b9ce4ac4cfe66ed"
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ from ba._stats import PlayerScoredMessage, PlayerRecord, Stats
|
|||||||
from ba._team import SessionTeam, Team, EmptyTeam
|
from ba._team import SessionTeam, Team, EmptyTeam
|
||||||
from ba._teamgame import TeamGameActivity
|
from ba._teamgame import TeamGameActivity
|
||||||
from ba._dualteamsession import DualTeamSession
|
from ba._dualteamsession import DualTeamSession
|
||||||
from ba._achievement import Achievement
|
from ba._achievement import Achievement, AchievementSubsystem
|
||||||
from ba._appconfig import AppConfig
|
from ba._appconfig import AppConfig
|
||||||
from ba._appdelegate import AppDelegate
|
from ba._appdelegate import AppDelegate
|
||||||
from ba._apputils import is_browser_likely_available
|
from ba._apputils import is_browser_likely_available
|
||||||
|
|||||||
@ -47,7 +47,7 @@ def get_league_rank_points(data: Optional[Dict[str, Any]],
|
|||||||
total_ach_value = data['at']
|
total_ach_value = data['at']
|
||||||
else:
|
else:
|
||||||
total_ach_value = 0
|
total_ach_value = 0
|
||||||
for ach in _ba.app.achievements:
|
for ach in _ba.app.ach.achievements:
|
||||||
if ach.complete:
|
if ach.complete:
|
||||||
total_ach_value += ach.power_ranking_value
|
total_ach_value += ach.power_ranking_value
|
||||||
|
|
||||||
|
|||||||
@ -6,9 +6,10 @@ from __future__ import annotations
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import _ba
|
import _ba
|
||||||
|
from ba._error import print_exception
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Any, Sequence, List, Dict, Union, Optional
|
from typing import Any, Sequence, List, Dict, Union, Optional, Tuple, Set
|
||||||
import ba
|
import ba
|
||||||
|
|
||||||
# This could use some cleanup.
|
# This could use some cleanup.
|
||||||
@ -61,69 +62,346 @@ ACH_LEVEL_NAMES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def award_local_achievement(achname: str) -> None:
|
class AchievementSubsystem:
|
||||||
"""For non-game-based achievements such as controller-connection ones."""
|
"""Subsystem for achievement handling.
|
||||||
try:
|
|
||||||
ach = get_achievement(achname)
|
|
||||||
if not ach.complete:
|
|
||||||
|
|
||||||
# Report new achievements to the game-service.
|
Category: App Classes
|
||||||
_ba.report_achievement(achname)
|
|
||||||
|
|
||||||
# And to our account.
|
Access the single shared instance of this class at 'ba.app.ach'.
|
||||||
_ba.add_transaction({'type': 'ACHIEVEMENT', 'name': achname})
|
|
||||||
|
|
||||||
# Now attempt to show a banner.
|
|
||||||
display_achievement_banner(achname)
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
from ba import _error
|
|
||||||
_error.print_exception()
|
|
||||||
|
|
||||||
|
|
||||||
def display_achievement_banner(achname: str) -> None:
|
|
||||||
"""Display a completion banner for an achievement.
|
|
||||||
|
|
||||||
Used for server-driven achievements.
|
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
# FIXME: Need to get these using the UI context or some other
|
|
||||||
# purely local context somehow instead of trying to inject these
|
|
||||||
# into whatever activity happens to be active
|
|
||||||
# (since that won't work while in client mode).
|
|
||||||
activity = _ba.get_foreground_host_activity()
|
|
||||||
if activity is not None:
|
|
||||||
with _ba.Context(activity):
|
|
||||||
get_achievement(achname).announce_completion()
|
|
||||||
except Exception:
|
|
||||||
from ba import _error
|
|
||||||
_error.print_exception('error showing server ach')
|
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.achievements: List[Achievement] = []
|
||||||
|
self.achievements_to_display: (List[Tuple[ba.Achievement, bool]]) = []
|
||||||
|
self.achievement_display_timer: Optional[_ba.Timer] = None
|
||||||
|
self.last_achievement_display_time: float = 0.0
|
||||||
|
self.achievement_completion_banner_slots: Set[int] = set()
|
||||||
|
self._init_achievements()
|
||||||
|
|
||||||
# This gets called whenever game-center/game-circle/etc tells us which
|
def _init_achievements(self) -> None:
|
||||||
# achievements we currently have. We always defer to them, even if that
|
"""Fill in available achievements."""
|
||||||
# means we have to un-set an achievement we think we have
|
|
||||||
|
|
||||||
|
achs = self.achievements
|
||||||
|
|
||||||
def set_completed_achievements(achs: Sequence[str]) -> None:
|
# 5
|
||||||
"""Set the current state of completed achievements.
|
achs.append(
|
||||||
|
Achievement('In Control', 'achievementInControl', (1, 1, 1), '',
|
||||||
|
5))
|
||||||
|
# 15
|
||||||
|
achs.append(
|
||||||
|
Achievement('Sharing is Caring', 'achievementSharingIsCaring',
|
||||||
|
(1, 1, 1), '', 15))
|
||||||
|
# 10
|
||||||
|
achs.append(
|
||||||
|
Achievement('Dual Wielding', 'achievementDualWielding', (1, 1, 1),
|
||||||
|
'', 10))
|
||||||
|
|
||||||
All achievements not included here will be set incomplete.
|
# 10
|
||||||
"""
|
achs.append(
|
||||||
cfg = _ba.app.config
|
Achievement('Free Loader', 'achievementFreeLoader', (1, 1, 1), '',
|
||||||
cfg['Achievements'] = {}
|
10))
|
||||||
for a_name in achs:
|
# 20
|
||||||
get_achievement(a_name).set_complete(True)
|
achs.append(
|
||||||
cfg.commit()
|
Achievement('Team Player', 'achievementTeamPlayer', (1, 1, 1), '',
|
||||||
|
20))
|
||||||
|
|
||||||
|
# 5
|
||||||
|
achs.append(
|
||||||
|
Achievement('Onslaught Training Victory', 'achievementOnslaught',
|
||||||
|
(1, 1, 1), 'Default:Onslaught Training', 5))
|
||||||
|
# 5
|
||||||
|
achs.append(
|
||||||
|
Achievement('Off You Go Then', 'achievementOffYouGo',
|
||||||
|
(1, 1.1, 1.3), 'Default:Onslaught Training', 5))
|
||||||
|
# 10
|
||||||
|
achs.append(
|
||||||
|
Achievement('Boxer',
|
||||||
|
'achievementBoxer', (1, 0.6, 0.6),
|
||||||
|
'Default:Onslaught Training',
|
||||||
|
10,
|
||||||
|
hard_mode_only=True))
|
||||||
|
|
||||||
def get_achievement(name: str) -> Achievement:
|
# 10
|
||||||
"""Return an Achievement by name."""
|
achs.append(
|
||||||
achs = [a for a in _ba.app.achievements if a.name == name]
|
Achievement('Rookie Onslaught Victory', 'achievementOnslaught',
|
||||||
assert len(achs) < 2
|
(0.5, 1.4, 0.6), 'Default:Rookie Onslaught', 10))
|
||||||
if not achs:
|
# 10
|
||||||
raise ValueError("Invalid achievement name: '" + name + "'")
|
achs.append(
|
||||||
return achs[0]
|
Achievement('Mine Games', 'achievementMine', (1, 1, 1.4),
|
||||||
|
'Default:Rookie Onslaught', 10))
|
||||||
|
# 15
|
||||||
|
achs.append(
|
||||||
|
Achievement('Flawless Victory',
|
||||||
|
'achievementFlawlessVictory', (1, 1, 1),
|
||||||
|
'Default:Rookie Onslaught',
|
||||||
|
15,
|
||||||
|
hard_mode_only=True))
|
||||||
|
|
||||||
|
# 10
|
||||||
|
achs.append(
|
||||||
|
Achievement('Rookie Football Victory',
|
||||||
|
'achievementFootballVictory', (1.0, 1, 0.6),
|
||||||
|
'Default:Rookie Football', 10))
|
||||||
|
# 10
|
||||||
|
achs.append(
|
||||||
|
Achievement('Super Punch', 'achievementSuperPunch', (1, 1, 1.8),
|
||||||
|
'Default:Rookie Football', 10))
|
||||||
|
# 15
|
||||||
|
achs.append(
|
||||||
|
Achievement('Rookie Football Shutout',
|
||||||
|
'achievementFootballShutout', (1, 1, 1),
|
||||||
|
'Default:Rookie Football',
|
||||||
|
15,
|
||||||
|
hard_mode_only=True))
|
||||||
|
|
||||||
|
# 15
|
||||||
|
achs.append(
|
||||||
|
Achievement('Pro Onslaught Victory', 'achievementOnslaught',
|
||||||
|
(0.3, 1, 2.0), 'Default:Pro Onslaught', 15))
|
||||||
|
# 15
|
||||||
|
achs.append(
|
||||||
|
Achievement('Boom Goes the Dynamite', 'achievementTNT',
|
||||||
|
(1.4, 1.2, 0.8), 'Default:Pro Onslaught', 15))
|
||||||
|
# 20
|
||||||
|
achs.append(
|
||||||
|
Achievement('Pro Boxer',
|
||||||
|
'achievementBoxer', (2, 2, 0),
|
||||||
|
'Default:Pro Onslaught',
|
||||||
|
20,
|
||||||
|
hard_mode_only=True))
|
||||||
|
|
||||||
|
# 15
|
||||||
|
achs.append(
|
||||||
|
Achievement('Pro Football Victory', 'achievementFootballVictory',
|
||||||
|
(1.3, 1.3, 2.0), 'Default:Pro Football', 15))
|
||||||
|
# 15
|
||||||
|
achs.append(
|
||||||
|
Achievement('Super Mega Punch', 'achievementSuperPunch',
|
||||||
|
(2, 1, 0.6), 'Default:Pro Football', 15))
|
||||||
|
# 20
|
||||||
|
achs.append(
|
||||||
|
Achievement('Pro Football Shutout',
|
||||||
|
'achievementFootballShutout', (0.7, 0.7, 2.0),
|
||||||
|
'Default:Pro Football',
|
||||||
|
20,
|
||||||
|
hard_mode_only=True))
|
||||||
|
|
||||||
|
# 15
|
||||||
|
achs.append(
|
||||||
|
Achievement('Pro Runaround Victory', 'achievementRunaround',
|
||||||
|
(1, 1, 1), 'Default:Pro Runaround', 15))
|
||||||
|
# 20
|
||||||
|
achs.append(
|
||||||
|
Achievement('Precision Bombing',
|
||||||
|
'achievementCrossHair', (1, 1, 1.3),
|
||||||
|
'Default:Pro Runaround',
|
||||||
|
20,
|
||||||
|
hard_mode_only=True))
|
||||||
|
# 25
|
||||||
|
achs.append(
|
||||||
|
Achievement('The Wall',
|
||||||
|
'achievementWall', (1, 0.7, 0.7),
|
||||||
|
'Default:Pro Runaround',
|
||||||
|
25,
|
||||||
|
hard_mode_only=True))
|
||||||
|
|
||||||
|
# 30
|
||||||
|
achs.append(
|
||||||
|
Achievement('Uber Onslaught Victory', 'achievementOnslaught',
|
||||||
|
(2, 2, 1), 'Default:Uber Onslaught', 30))
|
||||||
|
# 30
|
||||||
|
achs.append(
|
||||||
|
Achievement('Gold Miner',
|
||||||
|
'achievementMine', (2, 1.6, 0.2),
|
||||||
|
'Default:Uber Onslaught',
|
||||||
|
30,
|
||||||
|
hard_mode_only=True))
|
||||||
|
# 30
|
||||||
|
achs.append(
|
||||||
|
Achievement('TNT Terror',
|
||||||
|
'achievementTNT', (2, 1.8, 0.3),
|
||||||
|
'Default:Uber Onslaught',
|
||||||
|
30,
|
||||||
|
hard_mode_only=True))
|
||||||
|
|
||||||
|
# 30
|
||||||
|
achs.append(
|
||||||
|
Achievement('Uber Football Victory', 'achievementFootballVictory',
|
||||||
|
(1.8, 1.4, 0.3), 'Default:Uber Football', 30))
|
||||||
|
# 30
|
||||||
|
achs.append(
|
||||||
|
Achievement('Got the Moves',
|
||||||
|
'achievementGotTheMoves', (2, 1, 0),
|
||||||
|
'Default:Uber Football',
|
||||||
|
30,
|
||||||
|
hard_mode_only=True))
|
||||||
|
# 40
|
||||||
|
achs.append(
|
||||||
|
Achievement('Uber Football Shutout',
|
||||||
|
'achievementFootballShutout', (2, 2, 0),
|
||||||
|
'Default:Uber Football',
|
||||||
|
40,
|
||||||
|
hard_mode_only=True))
|
||||||
|
|
||||||
|
# 30
|
||||||
|
achs.append(
|
||||||
|
Achievement('Uber Runaround Victory', 'achievementRunaround',
|
||||||
|
(1.5, 1.2, 0.2), 'Default:Uber Runaround', 30))
|
||||||
|
# 40
|
||||||
|
achs.append(
|
||||||
|
Achievement('The Great Wall',
|
||||||
|
'achievementWall', (2, 1.7, 0.4),
|
||||||
|
'Default:Uber Runaround',
|
||||||
|
40,
|
||||||
|
hard_mode_only=True))
|
||||||
|
# 40
|
||||||
|
achs.append(
|
||||||
|
Achievement('Stayin\' Alive',
|
||||||
|
'achievementStayinAlive', (2, 2, 1),
|
||||||
|
'Default:Uber Runaround',
|
||||||
|
40,
|
||||||
|
hard_mode_only=True))
|
||||||
|
|
||||||
|
# 20
|
||||||
|
achs.append(
|
||||||
|
Achievement('Last Stand Master',
|
||||||
|
'achievementMedalSmall', (2, 1.5, 0.3),
|
||||||
|
'Default:The Last Stand',
|
||||||
|
20,
|
||||||
|
hard_mode_only=True))
|
||||||
|
# 40
|
||||||
|
achs.append(
|
||||||
|
Achievement('Last Stand Wizard',
|
||||||
|
'achievementMedalMedium', (2, 1.5, 0.3),
|
||||||
|
'Default:The Last Stand',
|
||||||
|
40,
|
||||||
|
hard_mode_only=True))
|
||||||
|
# 60
|
||||||
|
achs.append(
|
||||||
|
Achievement('Last Stand God',
|
||||||
|
'achievementMedalLarge', (2, 1.5, 0.3),
|
||||||
|
'Default:The Last Stand',
|
||||||
|
60,
|
||||||
|
hard_mode_only=True))
|
||||||
|
|
||||||
|
# 5
|
||||||
|
achs.append(
|
||||||
|
Achievement('Onslaught Master', 'achievementMedalSmall',
|
||||||
|
(0.7, 1, 0.7), 'Challenges:Infinite Onslaught', 5))
|
||||||
|
# 15
|
||||||
|
achs.append(
|
||||||
|
Achievement('Onslaught Wizard', 'achievementMedalMedium',
|
||||||
|
(0.7, 1.0, 0.7), 'Challenges:Infinite Onslaught', 15))
|
||||||
|
# 30
|
||||||
|
achs.append(
|
||||||
|
Achievement('Onslaught God', 'achievementMedalLarge',
|
||||||
|
(0.7, 1.0, 0.7), 'Challenges:Infinite Onslaught', 30))
|
||||||
|
|
||||||
|
# 5
|
||||||
|
achs.append(
|
||||||
|
Achievement('Runaround Master', 'achievementMedalSmall',
|
||||||
|
(1.0, 1.0, 1.2), 'Challenges:Infinite Runaround', 5))
|
||||||
|
# 15
|
||||||
|
achs.append(
|
||||||
|
Achievement('Runaround Wizard', 'achievementMedalMedium',
|
||||||
|
(1.0, 1.0, 1.2), 'Challenges:Infinite Runaround', 15))
|
||||||
|
# 30
|
||||||
|
achs.append(
|
||||||
|
Achievement('Runaround God', 'achievementMedalLarge',
|
||||||
|
(1.0, 1.0, 1.2), 'Challenges:Infinite Runaround', 30))
|
||||||
|
|
||||||
|
def award_local_achievement(self, achname: str) -> None:
|
||||||
|
"""For non-game-based achievements such as controller-connection."""
|
||||||
|
try:
|
||||||
|
ach = self.get_achievement(achname)
|
||||||
|
if not ach.complete:
|
||||||
|
|
||||||
|
# Report new achievements to the game-service.
|
||||||
|
_ba.report_achievement(achname)
|
||||||
|
|
||||||
|
# And to our account.
|
||||||
|
_ba.add_transaction({'type': 'ACHIEVEMENT', 'name': achname})
|
||||||
|
|
||||||
|
# Now attempt to show a banner.
|
||||||
|
self.display_achievement_banner(achname)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
print_exception()
|
||||||
|
|
||||||
|
def display_achievement_banner(self, achname: str) -> None:
|
||||||
|
"""Display a completion banner for an achievement.
|
||||||
|
|
||||||
|
(internal)
|
||||||
|
|
||||||
|
Used for server-driven achievements.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# FIXME: Need to get these using the UI context or some other
|
||||||
|
# purely local context somehow instead of trying to inject these
|
||||||
|
# into whatever activity happens to be active
|
||||||
|
# (since that won't work while in client mode).
|
||||||
|
activity = _ba.get_foreground_host_activity()
|
||||||
|
if activity is not None:
|
||||||
|
with _ba.Context(activity):
|
||||||
|
self.get_achievement(achname).announce_completion()
|
||||||
|
except Exception:
|
||||||
|
print_exception('error showing server ach')
|
||||||
|
|
||||||
|
def set_completed_achievements(self, achs: Sequence[str]) -> None:
|
||||||
|
"""Set the current state of completed achievements.
|
||||||
|
|
||||||
|
(internal)
|
||||||
|
|
||||||
|
All achievements not included here will be set incomplete.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Note: This gets called whenever game-center/game-circle/etc tells
|
||||||
|
# us which achievements we currently have. We always defer to them,
|
||||||
|
# even if that means we have to un-set an achievement we think we have.
|
||||||
|
|
||||||
|
cfg = _ba.app.config
|
||||||
|
cfg['Achievements'] = {}
|
||||||
|
for a_name in achs:
|
||||||
|
self.get_achievement(a_name).set_complete(True)
|
||||||
|
cfg.commit()
|
||||||
|
|
||||||
|
def get_achievement(self, name: str) -> Achievement:
|
||||||
|
"""Return an Achievement by name."""
|
||||||
|
achs = [a for a in self.achievements if a.name == name]
|
||||||
|
assert len(achs) < 2
|
||||||
|
if not achs:
|
||||||
|
raise ValueError("Invalid achievement name: '" + name + "'")
|
||||||
|
return achs[0]
|
||||||
|
|
||||||
|
def achievements_for_coop_level(self,
|
||||||
|
level_name: str) -> List[Achievement]:
|
||||||
|
"""Given a level name, return achievements available for it."""
|
||||||
|
|
||||||
|
# For the Easy campaign we return achievements for the Default
|
||||||
|
# campaign too. (want the user to see what achievements are part of the
|
||||||
|
# level even if they can't unlock them all on easy mode).
|
||||||
|
return [
|
||||||
|
a for a in self.achievements
|
||||||
|
if a.level_name in (level_name,
|
||||||
|
level_name.replace('Easy', 'Default'))
|
||||||
|
]
|
||||||
|
|
||||||
|
def _test(self) -> None:
|
||||||
|
"""For testing achievement animations."""
|
||||||
|
from ba._enums import TimeType
|
||||||
|
|
||||||
|
def testcall1() -> None:
|
||||||
|
self.achievements[0].announce_completion()
|
||||||
|
self.achievements[1].announce_completion()
|
||||||
|
self.achievements[2].announce_completion()
|
||||||
|
|
||||||
|
def testcall2() -> None:
|
||||||
|
self.achievements[3].announce_completion()
|
||||||
|
self.achievements[4].announce_completion()
|
||||||
|
self.achievements[5].announce_completion()
|
||||||
|
|
||||||
|
_ba.timer(3.0, testcall1, timetype=TimeType.BASE)
|
||||||
|
_ba.timer(7.0, testcall2, timetype=TimeType.BASE)
|
||||||
|
|
||||||
|
|
||||||
def _get_ach_mult(include_pro_bonus: bool = False) -> int:
|
def _get_ach_mult(include_pro_bonus: bool = False) -> int:
|
||||||
@ -139,34 +417,21 @@ def _get_ach_mult(include_pro_bonus: bool = False) -> int:
|
|||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
def get_achievements_for_coop_level(level_name: str) -> List[Achievement]:
|
|
||||||
"""Given a level name, return achievements available for it."""
|
|
||||||
|
|
||||||
# For the Easy campaign we return achievements for the Default
|
|
||||||
# campaign too. (want the user to see what achievements are part of the
|
|
||||||
# level even if they can't unlock them all on easy mode).
|
|
||||||
return [
|
|
||||||
a for a in _ba.app.achievements
|
|
||||||
if a.level_name in (level_name, level_name.replace('Easy', 'Default'))
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def _display_next_achievement() -> None:
|
def _display_next_achievement() -> None:
|
||||||
|
|
||||||
# Pull the first achievement off the list and display it, or kill the
|
# Pull the first achievement off the list and display it, or kill the
|
||||||
# display-timer if the list is empty.
|
# display-timer if the list is empty.
|
||||||
app = _ba.app
|
app = _ba.app
|
||||||
if app.achievements_to_display:
|
if app.ach.achievements_to_display:
|
||||||
try:
|
try:
|
||||||
ach, sound = app.achievements_to_display.pop(0)
|
ach, sound = app.ach.achievements_to_display.pop(0)
|
||||||
ach.show_completion_banner(sound)
|
ach.show_completion_banner(sound)
|
||||||
except Exception:
|
except Exception:
|
||||||
from ba import _error
|
print_exception('error showing next achievement')
|
||||||
_error.print_exception('error showing next achievement')
|
app.ach.achievements_to_display = []
|
||||||
app.achievements_to_display = []
|
app.ach.achievement_display_timer = None
|
||||||
app.achievement_display_timer = None
|
|
||||||
else:
|
else:
|
||||||
app.achievement_display_timer = None
|
app.ach.achievement_display_timer = None
|
||||||
|
|
||||||
|
|
||||||
class Achievement:
|
class Achievement:
|
||||||
@ -236,18 +501,18 @@ class Achievement:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# If we're being freshly complete, display/report it and whatnot.
|
# If we're being freshly complete, display/report it and whatnot.
|
||||||
if (self, sound) not in app.achievements_to_display:
|
if (self, sound) not in app.ach.achievements_to_display:
|
||||||
app.achievements_to_display.append((self, sound))
|
app.ach.achievements_to_display.append((self, sound))
|
||||||
|
|
||||||
# If there's no achievement display timer going, kick one off
|
# If there's no achievement display timer going, kick one off
|
||||||
# (if one's already running it will pick this up before it dies).
|
# (if one's already running it will pick this up before it dies).
|
||||||
|
|
||||||
# Need to check last time too; its possible our timer wasn't able to
|
# Need to check last time too; its possible our timer wasn't able to
|
||||||
# clear itself if an activity died and took it down with it.
|
# clear itself if an activity died and took it down with it.
|
||||||
if ((app.achievement_display_timer is None or
|
if ((app.ach.achievement_display_timer is None
|
||||||
_ba.time(TimeType.REAL) - app.last_achievement_display_time > 2.0)
|
or _ba.time(TimeType.REAL) - app.ach.last_achievement_display_time
|
||||||
and _ba.getactivity(doraise=False) is not None):
|
> 2.0) and _ba.getactivity(doraise=False) is not None):
|
||||||
app.achievement_display_timer = _ba.Timer(
|
app.ach.achievement_display_timer = _ba.Timer(
|
||||||
1.0,
|
1.0,
|
||||||
_display_next_achievement,
|
_display_next_achievement,
|
||||||
repeat=True,
|
repeat=True,
|
||||||
@ -280,9 +545,8 @@ class Achievement:
|
|||||||
else:
|
else:
|
||||||
name = ''
|
name = ''
|
||||||
except Exception:
|
except Exception:
|
||||||
from ba import _error
|
|
||||||
name = ''
|
name = ''
|
||||||
_error.print_exception()
|
print_exception()
|
||||||
return Lstr(resource='achievements.' + self._name + '.name',
|
return Lstr(resource='achievements.' + self._name + '.name',
|
||||||
subs=[('${LEVEL}', name)])
|
subs=[('${LEVEL}', name)])
|
||||||
|
|
||||||
@ -397,8 +661,7 @@ class Achievement:
|
|||||||
else:
|
else:
|
||||||
hmo = False
|
hmo = False
|
||||||
except Exception:
|
except Exception:
|
||||||
from ba import _error
|
print_exception('Error determining campaign.')
|
||||||
_error.print_exception('Error determining campaign')
|
|
||||||
hmo = False
|
hmo = False
|
||||||
|
|
||||||
objs: List[ba.Actor]
|
objs: List[ba.Actor]
|
||||||
@ -648,7 +911,7 @@ class Achievement:
|
|||||||
|
|
||||||
def _remove_banner_slot(self) -> None:
|
def _remove_banner_slot(self) -> None:
|
||||||
assert self._completion_banner_slot is not None
|
assert self._completion_banner_slot is not None
|
||||||
_ba.app.achievement_completion_banner_slots.remove(
|
_ba.app.ach.achievement_completion_banner_slots.remove(
|
||||||
self._completion_banner_slot)
|
self._completion_banner_slot)
|
||||||
self._completion_banner_slot = None
|
self._completion_banner_slot = None
|
||||||
|
|
||||||
@ -663,7 +926,7 @@ class Achievement:
|
|||||||
from ba._messages import DieMessage
|
from ba._messages import DieMessage
|
||||||
from ba._enums import TimeType, SpecialChar
|
from ba._enums import TimeType, SpecialChar
|
||||||
app = _ba.app
|
app = _ba.app
|
||||||
app.last_achievement_display_time = _ba.time(TimeType.REAL)
|
app.ach.last_achievement_display_time = _ba.time(TimeType.REAL)
|
||||||
|
|
||||||
# Just piggy-back onto any current activity
|
# Just piggy-back onto any current activity
|
||||||
# (should we use the session instead?..)
|
# (should we use the session instead?..)
|
||||||
@ -694,8 +957,8 @@ class Achievement:
|
|||||||
# Find the first free slot.
|
# Find the first free slot.
|
||||||
i = 0
|
i = 0
|
||||||
while True:
|
while True:
|
||||||
if i not in app.achievement_completion_banner_slots:
|
if i not in app.ach.achievement_completion_banner_slots:
|
||||||
app.achievement_completion_banner_slots.add(i)
|
app.ach.achievement_completion_banner_slots.add(i)
|
||||||
self._completion_banner_slot = i
|
self._completion_banner_slot = i
|
||||||
|
|
||||||
# Remove us from that slot when we close.
|
# Remove us from that slot when we close.
|
||||||
@ -953,252 +1216,3 @@ class Achievement:
|
|||||||
for actor in objs:
|
for actor in objs:
|
||||||
_ba.timer(out_time + 1.000,
|
_ba.timer(out_time + 1.000,
|
||||||
WeakCall(actor.handlemessage, DieMessage()))
|
WeakCall(actor.handlemessage, DieMessage()))
|
||||||
|
|
||||||
|
|
||||||
def init_achievements() -> None:
|
|
||||||
"""Fill in available achievements."""
|
|
||||||
|
|
||||||
achs = _ba.app.achievements
|
|
||||||
|
|
||||||
# 5
|
|
||||||
achs.append(
|
|
||||||
Achievement('In Control', 'achievementInControl', (1, 1, 1), '', 5))
|
|
||||||
# 15
|
|
||||||
achs.append(
|
|
||||||
Achievement('Sharing is Caring', 'achievementSharingIsCaring',
|
|
||||||
(1, 1, 1), '', 15))
|
|
||||||
# 10
|
|
||||||
achs.append(
|
|
||||||
Achievement('Dual Wielding', 'achievementDualWielding', (1, 1, 1), '',
|
|
||||||
10))
|
|
||||||
|
|
||||||
# 10
|
|
||||||
achs.append(
|
|
||||||
Achievement('Free Loader', 'achievementFreeLoader', (1, 1, 1), '', 10))
|
|
||||||
# 20
|
|
||||||
achs.append(
|
|
||||||
Achievement('Team Player', 'achievementTeamPlayer', (1, 1, 1), '', 20))
|
|
||||||
|
|
||||||
# 5
|
|
||||||
achs.append(
|
|
||||||
Achievement('Onslaught Training Victory', 'achievementOnslaught',
|
|
||||||
(1, 1, 1), 'Default:Onslaught Training', 5))
|
|
||||||
# 5
|
|
||||||
achs.append(
|
|
||||||
Achievement('Off You Go Then', 'achievementOffYouGo', (1, 1.1, 1.3),
|
|
||||||
'Default:Onslaught Training', 5))
|
|
||||||
# 10
|
|
||||||
achs.append(
|
|
||||||
Achievement('Boxer',
|
|
||||||
'achievementBoxer', (1, 0.6, 0.6),
|
|
||||||
'Default:Onslaught Training',
|
|
||||||
10,
|
|
||||||
hard_mode_only=True))
|
|
||||||
|
|
||||||
# 10
|
|
||||||
achs.append(
|
|
||||||
Achievement('Rookie Onslaught Victory', 'achievementOnslaught',
|
|
||||||
(0.5, 1.4, 0.6), 'Default:Rookie Onslaught', 10))
|
|
||||||
# 10
|
|
||||||
achs.append(
|
|
||||||
Achievement('Mine Games', 'achievementMine', (1, 1, 1.4),
|
|
||||||
'Default:Rookie Onslaught', 10))
|
|
||||||
# 15
|
|
||||||
achs.append(
|
|
||||||
Achievement('Flawless Victory',
|
|
||||||
'achievementFlawlessVictory', (1, 1, 1),
|
|
||||||
'Default:Rookie Onslaught',
|
|
||||||
15,
|
|
||||||
hard_mode_only=True))
|
|
||||||
|
|
||||||
# 10
|
|
||||||
achs.append(
|
|
||||||
Achievement('Rookie Football Victory', 'achievementFootballVictory',
|
|
||||||
(1.0, 1, 0.6), 'Default:Rookie Football', 10))
|
|
||||||
# 10
|
|
||||||
achs.append(
|
|
||||||
Achievement('Super Punch', 'achievementSuperPunch', (1, 1, 1.8),
|
|
||||||
'Default:Rookie Football', 10))
|
|
||||||
# 15
|
|
||||||
achs.append(
|
|
||||||
Achievement('Rookie Football Shutout',
|
|
||||||
'achievementFootballShutout', (1, 1, 1),
|
|
||||||
'Default:Rookie Football',
|
|
||||||
15,
|
|
||||||
hard_mode_only=True))
|
|
||||||
|
|
||||||
# 15
|
|
||||||
achs.append(
|
|
||||||
Achievement('Pro Onslaught Victory', 'achievementOnslaught',
|
|
||||||
(0.3, 1, 2.0), 'Default:Pro Onslaught', 15))
|
|
||||||
# 15
|
|
||||||
achs.append(
|
|
||||||
Achievement('Boom Goes the Dynamite', 'achievementTNT',
|
|
||||||
(1.4, 1.2, 0.8), 'Default:Pro Onslaught', 15))
|
|
||||||
# 20
|
|
||||||
achs.append(
|
|
||||||
Achievement('Pro Boxer',
|
|
||||||
'achievementBoxer', (2, 2, 0),
|
|
||||||
'Default:Pro Onslaught',
|
|
||||||
20,
|
|
||||||
hard_mode_only=True))
|
|
||||||
|
|
||||||
# 15
|
|
||||||
achs.append(
|
|
||||||
Achievement('Pro Football Victory', 'achievementFootballVictory',
|
|
||||||
(1.3, 1.3, 2.0), 'Default:Pro Football', 15))
|
|
||||||
# 15
|
|
||||||
achs.append(
|
|
||||||
Achievement('Super Mega Punch', 'achievementSuperPunch', (2, 1, 0.6),
|
|
||||||
'Default:Pro Football', 15))
|
|
||||||
# 20
|
|
||||||
achs.append(
|
|
||||||
Achievement('Pro Football Shutout',
|
|
||||||
'achievementFootballShutout', (0.7, 0.7, 2.0),
|
|
||||||
'Default:Pro Football',
|
|
||||||
20,
|
|
||||||
hard_mode_only=True))
|
|
||||||
|
|
||||||
# 15
|
|
||||||
achs.append(
|
|
||||||
Achievement('Pro Runaround Victory', 'achievementRunaround', (1, 1, 1),
|
|
||||||
'Default:Pro Runaround', 15))
|
|
||||||
# 20
|
|
||||||
achs.append(
|
|
||||||
Achievement('Precision Bombing',
|
|
||||||
'achievementCrossHair', (1, 1, 1.3),
|
|
||||||
'Default:Pro Runaround',
|
|
||||||
20,
|
|
||||||
hard_mode_only=True))
|
|
||||||
# 25
|
|
||||||
achs.append(
|
|
||||||
Achievement('The Wall',
|
|
||||||
'achievementWall', (1, 0.7, 0.7),
|
|
||||||
'Default:Pro Runaround',
|
|
||||||
25,
|
|
||||||
hard_mode_only=True))
|
|
||||||
|
|
||||||
# 30
|
|
||||||
achs.append(
|
|
||||||
Achievement('Uber Onslaught Victory', 'achievementOnslaught',
|
|
||||||
(2, 2, 1), 'Default:Uber Onslaught', 30))
|
|
||||||
# 30
|
|
||||||
achs.append(
|
|
||||||
Achievement('Gold Miner',
|
|
||||||
'achievementMine', (2, 1.6, 0.2),
|
|
||||||
'Default:Uber Onslaught',
|
|
||||||
30,
|
|
||||||
hard_mode_only=True))
|
|
||||||
# 30
|
|
||||||
achs.append(
|
|
||||||
Achievement('TNT Terror',
|
|
||||||
'achievementTNT', (2, 1.8, 0.3),
|
|
||||||
'Default:Uber Onslaught',
|
|
||||||
30,
|
|
||||||
hard_mode_only=True))
|
|
||||||
|
|
||||||
# 30
|
|
||||||
achs.append(
|
|
||||||
Achievement('Uber Football Victory', 'achievementFootballVictory',
|
|
||||||
(1.8, 1.4, 0.3), 'Default:Uber Football', 30))
|
|
||||||
# 30
|
|
||||||
achs.append(
|
|
||||||
Achievement('Got the Moves',
|
|
||||||
'achievementGotTheMoves', (2, 1, 0),
|
|
||||||
'Default:Uber Football',
|
|
||||||
30,
|
|
||||||
hard_mode_only=True))
|
|
||||||
# 40
|
|
||||||
achs.append(
|
|
||||||
Achievement('Uber Football Shutout',
|
|
||||||
'achievementFootballShutout', (2, 2, 0),
|
|
||||||
'Default:Uber Football',
|
|
||||||
40,
|
|
||||||
hard_mode_only=True))
|
|
||||||
|
|
||||||
# 30
|
|
||||||
achs.append(
|
|
||||||
Achievement('Uber Runaround Victory', 'achievementRunaround',
|
|
||||||
(1.5, 1.2, 0.2), 'Default:Uber Runaround', 30))
|
|
||||||
# 40
|
|
||||||
achs.append(
|
|
||||||
Achievement('The Great Wall',
|
|
||||||
'achievementWall', (2, 1.7, 0.4),
|
|
||||||
'Default:Uber Runaround',
|
|
||||||
40,
|
|
||||||
hard_mode_only=True))
|
|
||||||
# 40
|
|
||||||
achs.append(
|
|
||||||
Achievement('Stayin\' Alive',
|
|
||||||
'achievementStayinAlive', (2, 2, 1),
|
|
||||||
'Default:Uber Runaround',
|
|
||||||
40,
|
|
||||||
hard_mode_only=True))
|
|
||||||
|
|
||||||
# 20
|
|
||||||
achs.append(
|
|
||||||
Achievement('Last Stand Master',
|
|
||||||
'achievementMedalSmall', (2, 1.5, 0.3),
|
|
||||||
'Default:The Last Stand',
|
|
||||||
20,
|
|
||||||
hard_mode_only=True))
|
|
||||||
# 40
|
|
||||||
achs.append(
|
|
||||||
Achievement('Last Stand Wizard',
|
|
||||||
'achievementMedalMedium', (2, 1.5, 0.3),
|
|
||||||
'Default:The Last Stand',
|
|
||||||
40,
|
|
||||||
hard_mode_only=True))
|
|
||||||
# 60
|
|
||||||
achs.append(
|
|
||||||
Achievement('Last Stand God',
|
|
||||||
'achievementMedalLarge', (2, 1.5, 0.3),
|
|
||||||
'Default:The Last Stand',
|
|
||||||
60,
|
|
||||||
hard_mode_only=True))
|
|
||||||
|
|
||||||
# 5
|
|
||||||
achs.append(
|
|
||||||
Achievement('Onslaught Master', 'achievementMedalSmall', (0.7, 1, 0.7),
|
|
||||||
'Challenges:Infinite Onslaught', 5))
|
|
||||||
# 15
|
|
||||||
achs.append(
|
|
||||||
Achievement('Onslaught Wizard', 'achievementMedalMedium',
|
|
||||||
(0.7, 1.0, 0.7), 'Challenges:Infinite Onslaught', 15))
|
|
||||||
# 30
|
|
||||||
achs.append(
|
|
||||||
Achievement('Onslaught God', 'achievementMedalLarge', (0.7, 1.0, 0.7),
|
|
||||||
'Challenges:Infinite Onslaught', 30))
|
|
||||||
|
|
||||||
# 5
|
|
||||||
achs.append(
|
|
||||||
Achievement('Runaround Master', 'achievementMedalSmall',
|
|
||||||
(1.0, 1.0, 1.2), 'Challenges:Infinite Runaround', 5))
|
|
||||||
# 15
|
|
||||||
achs.append(
|
|
||||||
Achievement('Runaround Wizard', 'achievementMedalMedium',
|
|
||||||
(1.0, 1.0, 1.2), 'Challenges:Infinite Runaround', 15))
|
|
||||||
# 30
|
|
||||||
achs.append(
|
|
||||||
Achievement('Runaround God', 'achievementMedalLarge', (1.0, 1.0, 1.2),
|
|
||||||
'Challenges:Infinite Runaround', 30))
|
|
||||||
|
|
||||||
|
|
||||||
def _test() -> None:
|
|
||||||
"""For testing achievement animations."""
|
|
||||||
from ba._enums import TimeType
|
|
||||||
|
|
||||||
def testcall1() -> None:
|
|
||||||
app = _ba.app
|
|
||||||
app.achievements[0].announce_completion()
|
|
||||||
app.achievements[1].announce_completion()
|
|
||||||
app.achievements[2].announce_completion()
|
|
||||||
|
|
||||||
def testcall2() -> None:
|
|
||||||
app = _ba.app
|
|
||||||
app.achievements[3].announce_completion()
|
|
||||||
app.achievements[4].announce_completion()
|
|
||||||
app.achievements[5].announce_completion()
|
|
||||||
|
|
||||||
_ba.timer(3.0, testcall1, timetype=TimeType.BASE)
|
|
||||||
_ba.timer(7.0, testcall2, timetype=TimeType.BASE)
|
|
||||||
|
|||||||
@ -99,7 +99,6 @@ class App:
|
|||||||
"""Path where the app looks for its bundled scripts."""
|
"""Path where the app looks for its bundled scripts."""
|
||||||
assert isinstance(self._env['python_directory_app'], str)
|
assert isinstance(self._env['python_directory_app'], str)
|
||||||
return self._env['python_directory_app']
|
return self._env['python_directory_app']
|
||||||
# return self._python_directory_app
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def python_directory_app_site(self) -> str:
|
def python_directory_app_site(self) -> str:
|
||||||
@ -175,6 +174,7 @@ class App:
|
|||||||
from ba._music import MusicSubsystem
|
from ba._music import MusicSubsystem
|
||||||
from ba._language import LanguageSubsystem
|
from ba._language import LanguageSubsystem
|
||||||
from ba._ui import UISubsystem
|
from ba._ui import UISubsystem
|
||||||
|
from ba._achievement import AchievementSubsystem
|
||||||
|
|
||||||
# Config.
|
# Config.
|
||||||
self.config_file_healthy = False
|
self.config_file_healthy = False
|
||||||
@ -241,18 +241,10 @@ class App:
|
|||||||
self.last_ad_purpose = 'invalid'
|
self.last_ad_purpose = 'invalid'
|
||||||
self.attempted_first_ad = False
|
self.attempted_first_ad = False
|
||||||
|
|
||||||
# Music.
|
|
||||||
self.music = MusicSubsystem()
|
self.music = MusicSubsystem()
|
||||||
|
|
||||||
# Language.
|
|
||||||
self.lang = LanguageSubsystem()
|
self.lang = LanguageSubsystem()
|
||||||
|
self.ach = AchievementSubsystem()
|
||||||
# Achievements.
|
self.ui = UISubsystem()
|
||||||
self.achievements: List[ba.Achievement] = []
|
|
||||||
self.achievements_to_display: (List[Tuple[ba.Achievement, bool]]) = []
|
|
||||||
self.achievement_display_timer: Optional[_ba.Timer] = None
|
|
||||||
self.last_achievement_display_time: float = 0.0
|
|
||||||
self.achievement_completion_banner_slots: Set[int] = set()
|
|
||||||
|
|
||||||
# Lobby.
|
# Lobby.
|
||||||
self.lobby_random_profile_index: int = 1
|
self.lobby_random_profile_index: int = 1
|
||||||
@ -275,9 +267,6 @@ class App:
|
|||||||
self.ffa_series_length = 24
|
self.ffa_series_length = 24
|
||||||
self.coop_session_args: Dict = {}
|
self.coop_session_args: Dict = {}
|
||||||
|
|
||||||
# UI.
|
|
||||||
self.ui = UISubsystem()
|
|
||||||
|
|
||||||
self.value_test_defaults: dict = {}
|
self.value_test_defaults: dict = {}
|
||||||
self.first_main_menu = True # FIXME: Move to mainmenu class.
|
self.first_main_menu = True # FIXME: Move to mainmenu class.
|
||||||
self.did_menu_intro = False # FIXME: Move to mainmenu class.
|
self.did_menu_intro = False # FIXME: Move to mainmenu class.
|
||||||
@ -320,7 +309,7 @@ class App:
|
|||||||
|
|
||||||
self.ui.on_app_launch()
|
self.ui.on_app_launch()
|
||||||
|
|
||||||
_achievement.init_achievements()
|
# _achievement.init_achievements()
|
||||||
spazappearance.register_appearances()
|
spazappearance.register_appearances()
|
||||||
_campaign.init_campaigns()
|
_campaign.init_campaigns()
|
||||||
|
|
||||||
|
|||||||
@ -130,21 +130,19 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]):
|
|||||||
player.actor.handlemessage(CelebrateMessage(duration))
|
player.actor.handlemessage(CelebrateMessage(duration))
|
||||||
|
|
||||||
def _preload_achievements(self) -> None:
|
def _preload_achievements(self) -> None:
|
||||||
from ba import _achievement
|
achievements = _ba.app.ach.achievements_for_coop_level(
|
||||||
achievements = _achievement.get_achievements_for_coop_level(
|
|
||||||
self._get_coop_level_name())
|
self._get_coop_level_name())
|
||||||
for ach in achievements:
|
for ach in achievements:
|
||||||
ach.get_icon_texture(True)
|
ach.get_icon_texture(True)
|
||||||
|
|
||||||
def _show_remaining_achievements(self) -> None:
|
def _show_remaining_achievements(self) -> None:
|
||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from ba._achievement import get_achievements_for_coop_level
|
|
||||||
from ba._language import Lstr
|
from ba._language import Lstr
|
||||||
from bastd.actor.text import Text
|
from bastd.actor.text import Text
|
||||||
ts_h_offs = 30
|
ts_h_offs = 30
|
||||||
v_offs = -200
|
v_offs = -200
|
||||||
achievements = [
|
achievements = [
|
||||||
a for a in get_achievements_for_coop_level(
|
a for a in _ba.app.ach.achievements_for_coop_level(
|
||||||
self._get_coop_level_name()) if not a.complete
|
self._get_coop_level_name()) if not a.complete
|
||||||
]
|
]
|
||||||
vrmode = _ba.app.vr_mode
|
vrmode = _ba.app.vr_mode
|
||||||
@ -193,12 +191,11 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]):
|
|||||||
Returns True if a banner will be shown;
|
Returns True if a banner will be shown;
|
||||||
False otherwise
|
False otherwise
|
||||||
"""
|
"""
|
||||||
from ba._achievement import get_achievement
|
|
||||||
|
|
||||||
if achievement_name in self._achievements_awarded:
|
if achievement_name in self._achievements_awarded:
|
||||||
return
|
return
|
||||||
|
|
||||||
ach = get_achievement(achievement_name)
|
ach = _ba.app.ach.get_achievement(achievement_name)
|
||||||
|
|
||||||
# If we're in the easy campaign and this achievement is hard-mode-only,
|
# If we're in the easy campaign and this achievement is hard-mode-only,
|
||||||
# ignore it.
|
# ignore it.
|
||||||
|
|||||||
@ -138,13 +138,11 @@ def language_test_toggle() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def award_in_control_achievement() -> None:
|
def award_in_control_achievement() -> None:
|
||||||
from ba._achievement import award_local_achievement
|
_ba.app.ach.award_local_achievement('In Control')
|
||||||
award_local_achievement('In Control')
|
|
||||||
|
|
||||||
|
|
||||||
def award_dual_wielding_achievement() -> None:
|
def award_dual_wielding_achievement() -> None:
|
||||||
from ba._achievement import award_local_achievement
|
_ba.app.ach.award_local_achievement('Dual Wielding')
|
||||||
award_local_achievement('Dual Wielding')
|
|
||||||
|
|
||||||
|
|
||||||
def play_gong_sound() -> None:
|
def play_gong_sound() -> None:
|
||||||
|
|||||||
@ -121,7 +121,7 @@ class MusicSubsystem:
|
|||||||
|
|
||||||
Category: App Classes
|
Category: App Classes
|
||||||
|
|
||||||
To use this class, access the single instance of it at 'ba.app.music'.
|
Access the single shared instance of this class at 'ba.app.music'.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
|||||||
@ -6,11 +6,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING, TypeVar
|
from typing import TYPE_CHECKING, TypeVar
|
||||||
|
|
||||||
|
import _ba
|
||||||
from ba._freeforallsession import FreeForAllSession
|
from ba._freeforallsession import FreeForAllSession
|
||||||
from ba._gameactivity import GameActivity
|
from ba._gameactivity import GameActivity
|
||||||
from ba._gameresults import GameResults
|
from ba._gameresults import GameResults
|
||||||
from ba._dualteamsession import DualTeamSession
|
from ba._dualteamsession import DualTeamSession
|
||||||
import _ba
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Any, Dict, Type, Sequence
|
from typing import Any, Dict, Type, Sequence
|
||||||
@ -78,12 +78,11 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]):
|
|||||||
# Award a few achievements.
|
# Award a few achievements.
|
||||||
if isinstance(self.session, FreeForAllSession):
|
if isinstance(self.session, FreeForAllSession):
|
||||||
if len(self.players) >= 2:
|
if len(self.players) >= 2:
|
||||||
from ba import _achievement
|
_ba.app.ach.award_local_achievement('Free Loader')
|
||||||
_achievement.award_local_achievement('Free Loader')
|
|
||||||
elif isinstance(self.session, DualTeamSession):
|
elif isinstance(self.session, DualTeamSession):
|
||||||
if len(self.players) >= 4:
|
if len(self.players) >= 4:
|
||||||
from ba import _achievement
|
from ba import _achievement
|
||||||
_achievement.award_local_achievement('Team Player')
|
_ba.app.ach.award_local_achievement('Team Player')
|
||||||
except Exception:
|
except Exception:
|
||||||
from ba import _error
|
from ba import _error
|
||||||
_error.print_exception()
|
_error.print_exception()
|
||||||
|
|||||||
@ -23,9 +23,6 @@ from ba._account import (on_account_state_changed,
|
|||||||
get_purchased_icons, get_cached_league_rank_data,
|
get_purchased_icons, get_cached_league_rank_data,
|
||||||
get_league_rank_points, cache_league_rank_data)
|
get_league_rank_points, cache_league_rank_data)
|
||||||
from ba._activitytypes import JoinActivity, ScoreScreenActivity
|
from ba._activitytypes import JoinActivity, ScoreScreenActivity
|
||||||
from ba._achievement import (get_achievement, set_completed_achievements,
|
|
||||||
display_achievement_banner,
|
|
||||||
get_achievements_for_coop_level)
|
|
||||||
from ba._apputils import (is_browser_likely_available, get_remote_app_name,
|
from ba._apputils import (is_browser_likely_available, get_remote_app_name,
|
||||||
should_submit_debug_info, show_ad, show_ad_2)
|
should_submit_debug_info, show_ad, show_ad_2)
|
||||||
from ba._benchmark import (run_gpu_benchmark, run_cpu_benchmark,
|
from ba._benchmark import (run_gpu_benchmark, run_cpu_benchmark,
|
||||||
|
|||||||
@ -59,7 +59,6 @@ class CoopJoinActivity(JoinActivity):
|
|||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
from efro.util import asserttype
|
from efro.util import asserttype
|
||||||
from bastd.actor.text import Text
|
from bastd.actor.text import Text
|
||||||
from ba.internal import get_achievements_for_coop_level
|
|
||||||
|
|
||||||
# Sort by originating date so that the most recent is first.
|
# Sort by originating date so that the most recent is first.
|
||||||
if scores is not None:
|
if scores is not None:
|
||||||
@ -159,7 +158,8 @@ class CoopJoinActivity(JoinActivity):
|
|||||||
|
|
||||||
if not (ba.app.demo_mode or ba.app.arcade_mode):
|
if not (ba.app.demo_mode or ba.app.arcade_mode):
|
||||||
achievements = [
|
achievements = [
|
||||||
a for a in get_achievements_for_coop_level(levelname)
|
a
|
||||||
|
for a in ba.app.ach.achievements_for_coop_level(levelname)
|
||||||
if not a.complete
|
if not a.complete
|
||||||
]
|
]
|
||||||
have_achievements = bool(achievements)
|
have_achievements = bool(achievements)
|
||||||
|
|||||||
@ -10,7 +10,6 @@ from typing import TYPE_CHECKING
|
|||||||
|
|
||||||
import _ba
|
import _ba
|
||||||
import ba
|
import ba
|
||||||
from ba.internal import get_achievements_for_coop_level
|
|
||||||
from bastd.actor.text import Text
|
from bastd.actor.text import Text
|
||||||
from bastd.actor.zoomtext import ZoomText
|
from bastd.actor.zoomtext import ZoomText
|
||||||
|
|
||||||
@ -50,8 +49,8 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||||||
self._campaign: ba.Campaign = settings['campaign']
|
self._campaign: ba.Campaign = settings['campaign']
|
||||||
|
|
||||||
self._have_achievements = bool(
|
self._have_achievements = bool(
|
||||||
get_achievements_for_coop_level(self._campaign.name + ':' +
|
ba.app.ach.achievements_for_coop_level(self._campaign.name + ':' +
|
||||||
settings['level']))
|
settings['level']))
|
||||||
|
|
||||||
self._account_type = (_ba.get_account_type() if
|
self._account_type = (_ba.get_account_type() if
|
||||||
_ba.get_account_state() == 'signed_in' else None)
|
_ba.get_account_state() == 'signed_in' else None)
|
||||||
@ -847,7 +846,8 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||||||
transition_delay=2.8).autoretain()
|
transition_delay=2.8).autoretain()
|
||||||
|
|
||||||
assert self._game_name_str is not None
|
assert self._game_name_str is not None
|
||||||
achievements = get_achievements_for_coop_level(self._game_name_str)
|
achievements = ba.app.ach.achievements_for_coop_level(
|
||||||
|
self._game_name_str)
|
||||||
hval = -455
|
hval = -455
|
||||||
vval = -100
|
vval = -100
|
||||||
tdelay = 0.0
|
tdelay = 0.0
|
||||||
|
|||||||
@ -319,7 +319,8 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]):
|
|||||||
transition_out_delay=self._message_duration
|
transition_out_delay=self._message_duration
|
||||||
).autoretain()
|
).autoretain()
|
||||||
achs = [
|
achs = [
|
||||||
a for a in app.achievements if not a.complete
|
a for a in app.ach.achievements
|
||||||
|
if not a.complete
|
||||||
]
|
]
|
||||||
if achs:
|
if achs:
|
||||||
ach = achs.pop(
|
ach = achs.pop(
|
||||||
|
|||||||
@ -995,8 +995,8 @@ class AccountSettingsWindow(ba.Window):
|
|||||||
if (self._achievements_text is None
|
if (self._achievements_text is None
|
||||||
and self._achievements_button is None):
|
and self._achievements_button is None):
|
||||||
return
|
return
|
||||||
complete = sum(1 if a.complete else 0 for a in ba.app.achievements)
|
complete = sum(1 if a.complete else 0 for a in ba.app.ach.achievements)
|
||||||
total = len(ba.app.achievements)
|
total = len(ba.app.ach.achievements)
|
||||||
txt_final = ba.Lstr(resource=self._r + '.achievementProgressText',
|
txt_final = ba.Lstr(resource=self._r + '.achievementProgressText',
|
||||||
subs=[('${COUNT}', str(complete)),
|
subs=[('${COUNT}', str(complete)),
|
||||||
('${TOTAL}', str(total))])
|
('${TOTAL}', str(total))])
|
||||||
|
|||||||
@ -426,7 +426,7 @@ class AccountViewerWindow(popup.PopupWindow):
|
|||||||
v_align='center',
|
v_align='center',
|
||||||
scale=0.55,
|
scale=0.55,
|
||||||
text=str(data['achievementsCompleted']) + ' / ' +
|
text=str(data['achievementsCompleted']) + ' / ' +
|
||||||
str(len(ba.app.achievements)),
|
str(len(ba.app.ach.achievements)),
|
||||||
maxwidth=sub_width * maxwidth_scale)
|
maxwidth=sub_width * maxwidth_scale)
|
||||||
v -= 25
|
v -= 25
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@ class AchievementsWindow(popup.PopupWindow):
|
|||||||
icon=ba.gettexture('crossOut'),
|
icon=ba.gettexture('crossOut'),
|
||||||
iconscale=1.2)
|
iconscale=1.2)
|
||||||
|
|
||||||
achievements = ba.app.achievements
|
achievements = ba.app.ach.achievements
|
||||||
num_complete = len([a for a in achievements if a.complete])
|
num_complete = len([a for a in achievements if a.complete])
|
||||||
|
|
||||||
txt_final = ba.Lstr(
|
txt_final = ba.Lstr(
|
||||||
|
|||||||
@ -22,7 +22,7 @@ class GameButton:
|
|||||||
x: float, y: float, select: bool, row: str):
|
x: float, y: float, select: bool, row: str):
|
||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
from ba.internal import (get_achievements_for_coop_level, getcampaign)
|
from ba.internal import getcampaign
|
||||||
self._game = game
|
self._game = game
|
||||||
sclx = 195.0
|
sclx = 195.0
|
||||||
scly = 195.0
|
scly = 195.0
|
||||||
@ -81,7 +81,7 @@ class GameButton:
|
|||||||
mask_texture=ba.gettexture('mapPreviewMask'))
|
mask_texture=ba.gettexture('mapPreviewMask'))
|
||||||
|
|
||||||
translated = campaign.getlevel(levelname).displayname
|
translated = campaign.getlevel(levelname).displayname
|
||||||
self._achievements = (get_achievements_for_coop_level(game))
|
self._achievements = ba.app.ach.achievements_for_coop_level(game)
|
||||||
|
|
||||||
self._name_widget = ba.textwidget(parent=parent,
|
self._name_widget = ba.textwidget(parent=parent,
|
||||||
draw_controller=btn,
|
draw_controller=btn,
|
||||||
|
|||||||
@ -808,7 +808,7 @@ class LeagueRankWindow(ba.Window):
|
|||||||
# for the achievement value, use the number they gave us for
|
# for the achievement value, use the number they gave us for
|
||||||
# non-current seasons; otherwise calc our own
|
# non-current seasons; otherwise calc our own
|
||||||
total_ach_value = 0
|
total_ach_value = 0
|
||||||
for ach in ba.app.achievements:
|
for ach in ba.app.ach.achievements:
|
||||||
if ach.complete:
|
if ach.complete:
|
||||||
total_ach_value += ach.power_ranking_value
|
total_ach_value += ach.power_ranking_value
|
||||||
if self._season != 'a' and not self._is_current_season:
|
if self._season != 'a' and not self._is_current_season:
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||||
<h4><em>last updated on 2020-10-15 for Ballistica version 1.5.27 build 20218</em></h4>
|
<h4><em>last updated on 2020-10-16 for Ballistica version 1.5.27 build 20219</em></h4>
|
||||||
<p>This page documents the Python classes and functions in the 'ba' module,
|
<p>This page documents the Python classes and functions in the 'ba' module,
|
||||||
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
|
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
|
||||||
<hr>
|
<hr>
|
||||||
@ -148,6 +148,7 @@
|
|||||||
<h4><a name="class_category_App_Classes">App Classes</a></h4>
|
<h4><a name="class_category_App_Classes">App Classes</a></h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#class_ba_Achievement">ba.Achievement</a></li>
|
<li><a href="#class_ba_Achievement">ba.Achievement</a></li>
|
||||||
|
<li><a href="#class_ba_AchievementSubsystem">ba.AchievementSubsystem</a></li>
|
||||||
<li><a href="#class_ba_App">ba.App</a></li>
|
<li><a href="#class_ba_App">ba.App</a></li>
|
||||||
<li><a href="#class_ba_AppConfig">ba.AppConfig</a></li>
|
<li><a href="#class_ba_AppConfig">ba.AppConfig</a></li>
|
||||||
<li><a href="#class_ba_AppDelegate">ba.AppDelegate</a></li>
|
<li><a href="#class_ba_AppDelegate">ba.AppDelegate</a></li>
|
||||||
@ -350,6 +351,43 @@ actually award achievements.</p>
|
|||||||
|
|
||||||
<p>Create the banner/sound for an acquired achievement announcement.</p>
|
<p>Create the banner/sound for an acquired achievement announcement.</p>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<h2><strong><a name="class_ba_AchievementSubsystem">ba.AchievementSubsystem</a></strong></h3>
|
||||||
|
<p><em><top level class></em>
|
||||||
|
</p>
|
||||||
|
<p>Subsystem for achievement handling.</p>
|
||||||
|
|
||||||
|
<p>Category: <a href="#class_category_App_Classes">App Classes</a></p>
|
||||||
|
|
||||||
|
<p> Access the single shared instance of this class at 'ba.app.ach'.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Methods:</h3>
|
||||||
|
<h5><a href="#method_ba_AchievementSubsystem____init__"><constructor></a>, <a href="#method_ba_AchievementSubsystem__achievements_for_coop_level">achievements_for_coop_level()</a>, <a href="#method_ba_AchievementSubsystem__award_local_achievement">award_local_achievement()</a>, <a href="#method_ba_AchievementSubsystem__get_achievement">get_achievement()</a></h5>
|
||||||
|
<dl>
|
||||||
|
<dt><h4><a name="method_ba_AchievementSubsystem____init__"><constructor></a></dt></h4><dd>
|
||||||
|
<p><span>ba.AchievementSubsystem()</span></p>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt><h4><a name="method_ba_AchievementSubsystem__achievements_for_coop_level">achievements_for_coop_level()</a></dt></h4><dd>
|
||||||
|
<p><span>achievements_for_coop_level(self, level_name: str) -> List[Achievement]</span></p>
|
||||||
|
|
||||||
|
<p>Given a level name, return achievements available for it.</p>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt><h4><a name="method_ba_AchievementSubsystem__award_local_achievement">award_local_achievement()</a></dt></h4><dd>
|
||||||
|
<p><span>award_local_achievement(self, achname: str) -> None</span></p>
|
||||||
|
|
||||||
|
<p>For non-game-based achievements such as controller-connection.</p>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt><h4><a name="method_ba_AchievementSubsystem__get_achievement">get_achievement()</a></dt></h4><dd>
|
||||||
|
<p><span>get_achievement(self, name: str) -> Achievement</span></p>
|
||||||
|
|
||||||
|
<p>Return an Achievement by name.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<hr>
|
<hr>
|
||||||
@ -3974,7 +4012,7 @@ signify that the default soundtrack should be used..</p>
|
|||||||
|
|
||||||
<p>Category: <a href="#class_category_App_Classes">App Classes</a></p>
|
<p>Category: <a href="#class_category_App_Classes">App Classes</a></p>
|
||||||
|
|
||||||
<p> To use this class, access the single instance of it at 'ba.app.music'.
|
<p> Access the single shared instance of this class at 'ba.app.music'.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>Methods:</h3>
|
<h3>Methods:</h3>
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
namespace ballistica {
|
namespace ballistica {
|
||||||
|
|
||||||
// These are set automatically via script; don't change here.
|
// These are set automatically via script; don't change here.
|
||||||
const int kAppBuildNumber = 20218;
|
const int kAppBuildNumber = 20219;
|
||||||
const char* kAppVersion = "1.5.27";
|
const char* kAppVersion = "1.5.27";
|
||||||
|
|
||||||
// Our standalone globals.
|
// Our standalone globals.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user