diff --git a/.efrocachemap b/.efrocachemap
index 59faf8bb..6a883a28 100644
--- a/.efrocachemap
+++ b/.efrocachemap
@@ -4114,10 +4114,10 @@
"assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c",
"assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb",
"assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe",
- "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c4/9f/2df9fcc014404595eaa88a50d62b",
- "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/72/c0/fd83de83a099f829444778a65fac",
- "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/33/b77a77b8d82c616e2a66146cb6b3",
- "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cc/a6/f247e2bb7307cf759a791b39d876",
- "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c0/82/dc8e77df214bccf2dead8c25685b",
- "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1c/9b/45c1dafbe3e2556b4824ee5010ad"
+ "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/01/9f/6ce9331a09f15f2da1087d4ffba9",
+ "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/99/74/1709486aaf04f5fdd3f90ca0aab9",
+ "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/27/a6/5749795ec376cb5cdaf652dacdaa",
+ "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e9/ef/82e9a50695f333d68847585aa9a6",
+ "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c8/24/ac5bb7409ae0c5274e26a355a526",
+ "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/18/2e/cfa42c79a5024bb2111dfe347b51"
}
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4b33ee25..5a0a64d4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,8 +1,10 @@
name: CI
on:
- # Run on pushes and also once per day (in case deps change under us)
+ # Run on pushes, pull-requests, and also once per day
+ # (in case deps change under us, etc.)
push:
+ pull_request:
schedule:
# Note: '*' is a special character in YAML so we have to quote the str.
- cron: '0 12 * * *'
diff --git a/.idea/inspectionProfiles/Default.xml b/.idea/inspectionProfiles/Default.xml
index 2831a6dc..5639f88f 100644
--- a/.idea/inspectionProfiles/Default.xml
+++ b/.idea/inspectionProfiles/Default.xml
@@ -48,6 +48,7 @@
+
diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py
index b9078f4f..71267d9e 100644
--- a/assets/src/ba_data/python/_ba.py
+++ b/assets/src/ba_data/python/_ba.py
@@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand.
"""
# (hash we can use to see if this file is out of date)
-# SOURCES_HASH=92329394206923431348342003830010439152
+# SOURCES_HASH=262346642235815908245289158414705543661
# I'm sorry Pylint. I know this file saddens you. Be strong.
# pylint: disable=useless-suppression
@@ -3607,20 +3607,20 @@ def submit_analytics_counts() -> None:
def submit_score(game: str,
config: str,
name: Any,
- score: int,
+ score: Optional[int],
callback: Callable,
friend_callback: Optional[Callable],
order: str = 'increasing',
tournament_id: Optional[str] = None,
score_type: str = 'points',
- campaign: Optional[ba.Campaign] = None,
- level: Optional[ba.Level] = None) -> None:
- """submit_score(game: str, config: str, name: Any, score: int,
+ campaign: Optional[str] = None,
+ level: Optional[str] = None) -> None:
+ """submit_score(game: str, config: str, name: Any, score: Optional[int],
callback: Callable, friend_callback: Optional[Callable],
order: str = 'increasing', tournament_id: Optional[str] = None,
score_type: str = 'points',
- campaign: Optional[ba.Campaign] = None,
- level: Optional[ba.Level] = None) -> None
+ campaign: Optional[str] = None,
+ level: Optional[str] = None) -> None
(internal)
diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py
index 47742952..4478b4d2 100644
--- a/assets/src/ba_data/python/ba/__init__.py
+++ b/assets/src/ba_data/python/ba/__init__.py
@@ -74,11 +74,11 @@ from ba._general import WeakCall, Call
from ba._level import Level
from ba._lobby import Lobby, Chooser
from ba._math import normalized_color, is_point_in_box, vec3validate
-from ba._messages import (OutOfBoundsMessage, DieMessage, StandMessage,
- PickUpMessage, DropMessage, PickedUpMessage,
- DroppedMessage, ShouldShatterMessage,
- ImpactDamageMessage, FreezeMessage, ThawMessage,
- HitMessage)
+from ba._messages import (OutOfBoundsMessage, DeathType, DieMessage,
+ StandMessage, PickUpMessage, DropMessage,
+ PickedUpMessage, DroppedMessage,
+ ShouldShatterMessage, ImpactDamageMessage,
+ FreezeMessage, ThawMessage, HitMessage)
from ba._music import setmusic, MusicPlayer, MusicType, MusicPlayMode
from ba._powerup import PowerupMessage, PowerupAcceptMessage
from ba._teambasesession import TeamBaseSession
diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py
index 6372c376..4d43aace 100644
--- a/assets/src/ba_data/python/ba/_coopgame.py
+++ b/assets/src/ba_data/python/ba/_coopgame.py
@@ -172,16 +172,16 @@ class CoopGameActivity(GameActivity):
shadow=1.0 if vrmode else 0.5,
transition_delay=0.0,
transition_out_delay=1.3
- if self.slow_motion else 4000).autoretain()
+ if self.slow_motion else 4.0).autoretain()
hval = 70
vval = -50
- tdelay = 0
+ tdelay = 0.0
for ach in achievements:
- tdelay += 50
+ tdelay += 0.05
ach.create_display(hval + 40,
vval + v_offs,
0 + tdelay,
- outdelay=1300 if self.slow_motion else 4000,
+ outdelay=1.3 if self.slow_motion else 4.0,
style='in_game')
vval -= 55
diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py
index 3ef4c817..f30f2316 100644
--- a/assets/src/ba_data/python/ba/_coopsession.py
+++ b/assets/src/ba_data/python/ba/_coopsession.py
@@ -72,7 +72,7 @@ class CoopSession(Session):
except Exception:
max_players = 4
- print('FIXME: COOP SESSION WOULD CALC DEPS.')
+ # print('FIXME: COOP SESSION WOULD CALC DEPS.')
depsets: Sequence[ba.DependencySet] = []
super().__init__(depsets,
diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py
index 8f817f63..67999626 100644
--- a/assets/src/ba_data/python/ba/_gameactivity.py
+++ b/assets/src/ba_data/python/ba/_gameactivity.py
@@ -658,7 +658,7 @@ class GameActivity(Activity):
def on_player_leave(self, player: ba.Player) -> None:
from ba._general import Call
- from ba._messages import DieMessage
+ from ba._messages import DieMessage, DeathType
super().on_player_leave(player)
@@ -668,7 +668,8 @@ class GameActivity(Activity):
# will incorrectly try to respawn them, etc.
actor = player.actor
if actor is not None:
- _ba.pushcall(Call(actor.handlemessage, DieMessage(how='leftGame')))
+ _ba.pushcall(
+ Call(actor.handlemessage, DieMessage(how=DeathType.LEFT_GAME)))
player.set_actor(None)
def handlemessage(self, msg: Any) -> Any:
@@ -679,9 +680,9 @@ class GameActivity(Activity):
killer = msg.killerplayer
# Inform our score-set of the demise.
- self.stats.player_lost_spaz(player,
- killed=msg.killed,
- killer=killer)
+ self.stats.player_was_killed(player,
+ killed=msg.killed,
+ killer=killer)
# Award the killer points if he's on a different team.
if killer and killer.team is not player.team:
@@ -1070,7 +1071,6 @@ class GameActivity(Activity):
spaz.node.name = name
spaz.node.name_color = display_color
spaz.connect_controls_to_player()
- self.stats.player_got_new_spaz(player, spaz)
# Move to the stand position and add a flash of light.
spaz.handlemessage(
diff --git a/assets/src/ba_data/python/ba/_messages.py b/assets/src/ba_data/python/ba/_messages.py
index ad06a1c9..a82bd481 100644
--- a/assets/src/ba_data/python/ba/_messages.py
+++ b/assets/src/ba_data/python/ba/_messages.py
@@ -24,6 +24,7 @@ from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING
+from enum import Enum
import _ba
@@ -40,6 +41,18 @@ class OutOfBoundsMessage:
"""
+class DeathType(Enum):
+ """A reason for a death.
+
+ Category: Enums
+ """
+ GENERIC = 'generic'
+ IMPACT = 'impact'
+ FALL = 'fall'
+ REACHED_GOAL = 'reached_goal'
+ LEFT_GAME = 'left_game'
+
+
@dataclass
class DieMessage:
"""A message telling an object to die.
@@ -57,12 +70,11 @@ class DieMessage:
its time with lingering corpses, sound effects, etc.
how
- The particular reason for death; 'fall', 'impact', 'leftGame', etc.
- This can be examined for scoring or other purposes.
+ The particular reason for death.
"""
immediate: bool = False
- how: str = 'generic'
+ how: DeathType = DeathType.GENERIC
@dataclass
diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py
index 54d5a1c7..6954aea2 100644
--- a/assets/src/ba_data/python/ba/_stats.py
+++ b/assets/src/ba_data/python/ba/_stats.py
@@ -72,12 +72,11 @@ class PlayerRecord:
self.killed_count = 0
self.accum_killed_count = 0
self._multi_kill_timer: Optional[ba.Timer] = None
- self._multikillcount = 0
+ self._multi_kill_count = 0
self._stats = weakref.ref(stats)
self._last_player: Optional[ba.Player] = None
self._player: Optional[ba.Player] = None
self.associate_with_player(player)
- self._spaz: Optional[ReferenceType[ba.Actor]] = None
self._team: Optional[ReferenceType[ba.Team]] = None
self.streak = 0
@@ -115,16 +114,6 @@ class PlayerRecord:
assert player is not None
return player.get_icon()
- def get_spaz(self) -> Optional[ba.Actor]:
- """Return the player entry's spaz."""
- if self._spaz is None:
- return None
- return self._spaz()
-
- def set_spaz(self, spaz: Optional[ba.Actor]) -> None:
- """(internal)"""
- self._spaz = weakref.ref(spaz) if spaz is not None else None
-
def cancel_multi_kill_timer(self) -> None:
"""Cancel any multi-kill timer for this player entry."""
self._multi_kill_timer = None
@@ -144,12 +133,11 @@ class PlayerRecord:
self.character = player.character
self._last_player = player
self._player = player
- self._spaz = None
self.streak = 0
def _end_multi_kill(self) -> None:
self._multi_kill_timer = None
- self._multikillcount = 0
+ self._multi_kill_count = 0
def get_last_player(self) -> ba.Player:
"""Return the last ba.Player we were associated with."""
@@ -162,52 +150,51 @@ class PlayerRecord:
# pylint: disable=too-many-statements
from ba._lang import Lstr
from ba._general import Call
- from ba._enums import TimeFormat
- self._multikillcount += 1
+ self._multi_kill_count += 1
stats = self._stats()
assert stats
- if self._multikillcount == 1:
+ if self._multi_kill_count == 1:
score = 0
name = None
- delay = 0
+ delay = 0.0
color = (0.0, 0.0, 0.0, 1.0)
scale = 1.0
sound = None
- elif self._multikillcount == 2:
+ elif self._multi_kill_count == 2:
score = 20
name = Lstr(resource='twoKillText')
color = (0.1, 1.0, 0.0, 1)
scale = 1.0
- delay = 0
+ delay = 0.0
sound = stats.orchestrahitsound1
- elif self._multikillcount == 3:
+ elif self._multi_kill_count == 3:
score = 40
name = Lstr(resource='threeKillText')
color = (1.0, 0.7, 0.0, 1)
scale = 1.1
- delay = 300
+ delay = 0.3
sound = stats.orchestrahitsound2
- elif self._multikillcount == 4:
+ elif self._multi_kill_count == 4:
score = 60
name = Lstr(resource='fourKillText')
color = (1.0, 1.0, 0.0, 1)
scale = 1.2
- delay = 600
+ delay = 0.6
sound = stats.orchestrahitsound3
- elif self._multikillcount == 5:
+ elif self._multi_kill_count == 5:
score = 80
name = Lstr(resource='fiveKillText')
color = (1.0, 0.5, 0.0, 1)
scale = 1.3
- delay = 900
+ delay = 0.9
sound = stats.orchestrahitsound4
else:
score = 100
name = Lstr(resource='multiKillText',
- subs=[('${COUNT}', str(self._multikillcount))])
+ subs=[('${COUNT}', str(self._multi_kill_count))])
color = (1.0, 0.5, 0.0, 1)
scale = 1.3
- delay = 1000
+ delay = 1.0
sound = stats.orchestrahitsound4
def _apply(name2: Lstr, score2: int, showpoints2: bool,
@@ -217,12 +204,9 @@ class PlayerRecord:
# Only award this if they're still alive and we can get
# their pos.
- try:
- actor = self.get_spaz()
- assert actor is not None
- assert actor.node
- our_pos = actor.node.position
- except Exception:
+ if self._player is not None and self._player.node:
+ our_pos = self._player.node.position
+ else:
return
# Jitter position a bit since these often come in clusters.
@@ -249,10 +233,9 @@ class PlayerRecord:
activity.handlemessage(PlayerScoredMessage(score=score2))
if name is not None:
- _ba.timer(300 + delay,
- Call(_apply, name, score, showpoints, color, scale,
- sound),
- timeformat=TimeFormat.MILLISECONDS)
+ _ba.timer(
+ 0.3 + delay,
+ Call(_apply, name, score, showpoints, color, scale, sound))
# Keep the tally rollin'...
# set a timer for a bit in the future.
@@ -304,6 +287,7 @@ class Stats:
def reset(self) -> None:
"""Reset the stats instance completely."""
+
# Just to be safe, lets make sure no multi-kill timers are gonna go off
# for no-longer-on-the-list players.
for p_entry in list(self._player_records.values()):
@@ -345,17 +329,6 @@ class Stats:
records[record_id] = record
return records
- def _get_spaz(self, player: ba.Player) -> Optional[ba.Actor]:
- return self._player_records[player.get_name()].get_spaz()
-
- def player_got_new_spaz(self, player: ba.Player, spaz: ba.Actor) -> None:
- """Call this when a player gets a new Spaz."""
- record = self._player_records[player.get_name()]
- if record.get_spaz() is not None:
- raise Exception("got 2 player_got_new_spaz() messages in a row"
- " without a lost-spaz message")
- record.set_spaz(spaz)
-
def player_got_hit(self, player: ba.Player) -> None:
"""Call this when a player got hit."""
s_player = self._player_records[player.get_name()]
@@ -388,7 +361,7 @@ class Stats:
from ba import _math
from ba._gameactivity import GameActivity
from ba._lang import Lstr
- del victim_player # currently unused
+ del victim_player # Currently unused.
name = player.get_name()
s_player = self._player_records[name]
@@ -418,16 +391,9 @@ class Stats:
from ba import _error
_error.print_exception('error showing big_message')
- # If we currently have a spaz, pop up a score over it.
+ # If we currently have a actor, pop up a score over it.
if display and showpoints:
- our_pos: Optional[Sequence[float]]
- try:
- spaz = s_player.get_spaz()
- assert spaz is not None
- assert spaz.node
- our_pos = spaz.node.position
- except Exception:
- our_pos = None
+ our_pos = player.node.position if player.node else None
if our_pos is not None:
if target is None:
target = our_pos
@@ -478,15 +444,14 @@ class Stats:
return points
- def player_lost_spaz(self,
- player: ba.Player,
- killed: bool = False,
- killer: ba.Player = None) -> None:
- """Should be called when a player loses a spaz."""
+ def player_was_killed(self,
+ player: ba.Player,
+ killed: bool = False,
+ killer: ba.Player = None) -> None:
+ """Should be called when a player is killed."""
from ba._lang import Lstr
name = player.get_name()
prec = self._player_records[name]
- prec.set_spaz(None)
prec.streak = 0
if killed:
prec.accum_killed_count += 1
diff --git a/assets/src/ba_data/python/bastd/activity/coopscorescreen.py b/assets/src/ba_data/python/bastd/activity/coopscorescreen.py
index b0ef4ab4..b0fb56f8 100644
--- a/assets/src/ba_data/python/bastd/activity/coopscorescreen.py
+++ b/assets/src/ba_data/python/bastd/activity/coopscorescreen.py
@@ -66,9 +66,11 @@ class CoopScoreScreen(ba.Activity):
self._menu_icon_texture = ba.gettexture('menuIcon')
self._next_level_icon_texture = ba.gettexture('nextLevelIcon')
+ self._campaign: ba.Campaign = settings['campaign']
+
self._have_achievements = bool(
- get_achievements_for_coop_level(settings['campaign'].get_name() +
- ":" + settings['level']))
+ get_achievements_for_coop_level(self._campaign.name + ":" +
+ settings['level']))
self._account_type = (_ba.get_account_type() if
_ba.get_account_state() == 'signed_in' else None)
@@ -122,12 +124,12 @@ class CoopScoreScreen(ba.Activity):
self._next_level_error: Optional[ba.Actor] = None
# Score/gameplay bits.
- self._was_complete = None
- self._is_complete = None
- self._newly_complete = None
- self._is_more_levels = None
- self._next_level_name = None
- self._show_friend_scores = None
+ self._was_complete: Optional[bool] = None
+ self._is_complete: Optional[bool] = None
+ self._newly_complete: Optional[bool] = None
+ self._is_more_levels: Optional[bool] = None
+ self._next_level_name: Optional[str] = None
+ self._show_friend_scores: Optional[bool] = None
self._show_info: Optional[Dict[str, Any]] = None
self._name_str: Optional[str] = None
self._friends_loading_status: Optional[ba.Actor] = None
@@ -135,9 +137,15 @@ class CoopScoreScreen(ba.Activity):
self._tournament_time_remaining_text_timer: Optional[ba.Timer] = None
self._player_info = settings['player_info']
- self._score = settings['score']
- self._fail_message = settings['fail_message']
+ self._score: Optional[int] = settings['score']
+ assert isinstance(self._score, (int, type(None)))
+
+ self._fail_message: Optional[str] = settings['fail_message']
+ assert isinstance(self._fail_message, (str, type(None)))
+
self._begin_time = ba.time()
+
+ self._score_order: str
if 'score_order' in settings:
if not settings['score_order'] in ['increasing', 'decreasing']:
raise Exception("Invalid score order: " +
@@ -145,7 +153,9 @@ class CoopScoreScreen(ba.Activity):
self._score_order = settings['score_order']
else:
self._score_order = 'increasing'
+ assert isinstance(self._score_order, str)
+ self._score_type: str
if 'score_type' in settings:
if not settings['score_type'] in ['points', 'time']:
raise Exception("Invalid score type: " +
@@ -153,12 +163,12 @@ class CoopScoreScreen(ba.Activity):
self._score_type = settings['score_type']
else:
self._score_type = 'points'
+ assert isinstance(self._score_type, str)
- self._campaign = settings['campaign']
- self._level_name = settings['level']
+ self._level_name: str = settings['level']
+ assert isinstance(self._level_name, str)
- self._game_name_str = self._campaign.get_name(
- ) + ":" + self._level_name
+ self._game_name_str = self._campaign.name + ":" + self._level_name
self._game_config_str = str(len(
self._player_info)) + "p" + self._campaign.get_level(
self._level_name).get_score_version_string().replace(' ', '_')
@@ -170,11 +180,11 @@ class CoopScoreScreen(ba.Activity):
try:
self._old_best_rank = self._campaign.get_level(
- self._level_name).get_rating()
+ self._level_name).rating
except Exception:
self._old_best_rank = 0.0
- self._victory = (settings['outcome'] == 'victory')
+ self._victory: bool = settings['outcome'] == 'victory'
def __del__(self) -> None:
super().__del__()
@@ -255,6 +265,7 @@ class CoopScoreScreen(ba.Activity):
# next one, set it as current (this won't happen otherwise).
if (self._is_complete and self._is_more_levels
and not self._newly_complete):
+ assert self._next_level_name is not None
self._campaign.set_selected_level(self._next_level_name)
ba.containerwidget(edit=self._root_ui, transition='out_left')
with ba.Context(self):
@@ -294,7 +305,7 @@ class CoopScoreScreen(ba.Activity):
ba.DieMessage()))
def _should_show_worlds_best_button(self) -> bool:
- # link is too complicated to display with no browser
+ # Link is too complicated to display with no browser.
return ba.is_browser_likely_available()
def request_ui(self) -> None:
@@ -511,26 +522,26 @@ class CoopScoreScreen(ba.Activity):
# Calc whether the level is complete and other stuff.
levels = self._campaign.get_levels()
level = self._campaign.get_level(self._level_name)
- self._was_complete = level.get_complete()
+ self._was_complete = level.complete
self._is_complete = (self._was_complete or self._victory)
self._newly_complete = (self._is_complete and not self._was_complete)
- self._is_more_levels = ((level.get_index() < len(levels) - 1)
- and self._campaign.is_sequential())
+ self._is_more_levels = ((level.index < len(levels) - 1)
+ and self._campaign.sequential)
# Any time we complete a level, set the next one as unlocked.
if self._is_complete and self._is_more_levels:
_ba.add_transaction({
'type': 'COMPLETE_LEVEL',
- 'campaign': self._campaign.get_name(),
+ 'campaign': self._campaign.name,
'level': self._level_name
})
- self._next_level_name = levels[level.get_index() + 1].get_name()
+ self._next_level_name = levels[level.index + 1].name
# If this is the first time we completed it, set the next one
# as current.
if self._newly_complete:
cfg = ba.app.config
- cfg['Selected Coop Game'] = (self._campaign.get_name() + ":" +
+ cfg['Selected Coop Game'] = (self._campaign.name + ":" +
self._next_level_name)
cfg.commit()
self._campaign.set_selected_level(self._next_level_name)
@@ -577,8 +588,7 @@ class CoopScoreScreen(ba.Activity):
pstr = ba.Lstr(value='- ${A} -',
subs=[('${A}',
ba.Lstr(resource='singlePlayerCountText'))])
- ZoomText(self._campaign.get_level(
- self._level_name).get_display_string(),
+ ZoomText(self._campaign.get_level(self._level_name).displayname,
maxwidth=800,
flash=False,
trail=False,
@@ -614,7 +624,7 @@ class CoopScoreScreen(ba.Activity):
ba.timer(0.35,
ba.Call(ba.playsound, self._score_display_sound_small))
- # Vestigial remain.. this stuff should just be instance vars.
+ # Vestigial remain; this stuff should just be instance vars.
self._show_info = {}
if self._score is not None:
@@ -678,13 +688,13 @@ class CoopScoreScreen(ba.Activity):
self._level_name).get_score_version_string())
_ba.add_transaction({
'type': 'SET_LEVEL_LOCAL_HIGH_SCORES',
- 'campaign': self._campaign.get_name(),
+ 'campaign': self._campaign.name,
'level': self._level_name,
'scoreVersion': sver,
'scores': our_high_scores_all
})
if _ba.get_account_state() != 'signed_in':
- # we expect this only in kiosk mode; complain otherwise..
+ # We expect this only in kiosk mode; complain otherwise.
if not ba.app.kiosk_mode:
print('got not-signed-in at score-submit; unexpected')
if self._show_friend_scores:
@@ -703,7 +713,7 @@ class CoopScoreScreen(ba.Activity):
order=self._score_order,
tournament_id=self.session.tournament_id,
score_type=self._score_type,
- campaign=self._campaign.get_name()
+ campaign=self._campaign.name
if self._campaign is not None else None,
level=self._level_name)
@@ -1373,8 +1383,7 @@ class CoopScoreScreen(ba.Activity):
dostar(2, 10 - 30, -112, '7.5')
dostar(3, 77 - 30, -112, '9.5')
try:
- best_rank = self._campaign.get_level(
- self._level_name).get_rating()
+ best_rank = self._campaign.get_level(self._level_name).rating
except Exception:
best_rank = 0.0
@@ -1449,6 +1458,8 @@ class CoopScoreScreen(ba.Activity):
def _show_score_val(self, offs_x: float) -> None:
from bastd.actor.text import Text
from bastd.actor.zoomtext import ZoomText
+ assert self._score_type is not None
+ assert self._score is not None
ZoomText((str(self._score) if self._score_type == 'points' else
ba.timestring(self._score * 10,
timeformat=ba.TimeFormat.MILLISECONDS)),
diff --git a/assets/src/ba_data/python/bastd/actor/background.py b/assets/src/ba_data/python/bastd/actor/background.py
index 20558d1f..02811c7c 100644
--- a/assets/src/ba_data/python/bastd/actor/background.py
+++ b/assets/src/ba_data/python/bastd/actor/background.py
@@ -150,7 +150,7 @@ class Background(ba.Actor):
ba.timer(self.fade_time + 0.1, self.node.delete)
def handlemessage(self, msg: Any) -> Any:
- if __debug__ is True:
+ if __debug__:
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage):
self._die(msg.immediate)
diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py
index 7ed0e05e..3d520d4a 100644
--- a/assets/src/ba_data/python/bastd/actor/bomb.py
+++ b/assets/src/ba_data/python/bastd/actor/bomb.py
@@ -776,8 +776,8 @@ class Bomb(ba.Actor):
self.arm_timer = ba.Timer(
0.2, ba.WeakCall(self.handlemessage, ArmMessage()))
self.warn_timer = ba.Timer(
- 0.001 * (fuse_time - 1.7),
- ba.WeakCall(self.handlemessage, WarnMessage()))
+ fuse_time - 1.7, ba.WeakCall(self.handlemessage,
+ WarnMessage()))
else:
fuse_time = 3.0
diff --git a/assets/src/ba_data/python/bastd/actor/controlsguide.py b/assets/src/ba_data/python/bastd/actor/controlsguide.py
index e6916227..8809cc69 100644
--- a/assets/src/ba_data/python/bastd/actor/controlsguide.py
+++ b/assets/src/ba_data/python/bastd/actor/controlsguide.py
@@ -469,7 +469,7 @@ class ControlsGuide(ba.Actor):
return not self._dead
def handlemessage(self, msg: Any) -> Any:
- if __debug__ is True:
+ if __debug__:
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage):
if msg.immediate:
diff --git a/assets/src/ba_data/python/bastd/actor/flag.py b/assets/src/ba_data/python/bastd/actor/flag.py
index b62055fd..6ef08a63 100644
--- a/assets/src/ba_data/python/bastd/actor/flag.py
+++ b/assets/src/ba_data/python/bastd/actor/flag.py
@@ -350,7 +350,7 @@ class Flag(ba.Actor):
elif isinstance(msg, ba.OutOfBoundsMessage):
# We just kill ourselves when out-of-bounds.. would we ever not
# want this?..
- self.handlemessage(ba.DieMessage(how='fall'))
+ self.handlemessage(ba.DieMessage(how=ba.DeathType.FALL))
elif isinstance(msg, ba.PickedUpMessage):
self._held_count += 1
if self._held_count == 1 and self._counter is not None:
diff --git a/assets/src/ba_data/python/bastd/actor/image.py b/assets/src/ba_data/python/bastd/actor/image.py
index 07bffd73..6b4d1a32 100644
--- a/assets/src/ba_data/python/bastd/actor/image.py
+++ b/assets/src/ba_data/python/bastd/actor/image.py
@@ -51,8 +51,9 @@ class Image(ba.Actor):
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
super().__init__()
- # if they provided a dict as texture, assume its an icon..
- # otherwise its just a texture value itself
+
+ # If they provided a dict as texture, assume its an icon.
+ # otherwise its just a texture value itself.
mask_texture: Optional[ba.Texture]
if isinstance(texture, dict):
tint_color = texture['tint_color']
@@ -156,13 +157,13 @@ class Image(ba.Actor):
cmb.input1 = position[1]
cmb.connectattr('output', self.node, 'position')
- # if we're transitioning out, die at the end of it
+ # If we're transitioning out, die at the end of it.
if transition_out_delay is not None:
ba.timer(transition_delay + transition_out_delay + 1.0,
ba.WeakCall(self.handlemessage, ba.DieMessage()))
def handlemessage(self, msg: Any) -> Any:
- if __debug__ is True:
+ if __debug__:
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage):
if self.node:
diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py
index 1af781fc..a600f3a9 100644
--- a/assets/src/ba_data/python/bastd/actor/playerspaz.py
+++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py
@@ -53,7 +53,7 @@ class PlayerSpazDeathMessage:
"""
def __init__(self, spaz: PlayerSpaz, was_killed: bool,
- killerplayer: Optional[ba.Player], how: str):
+ killerplayer: Optional[ba.Player], how: ba.DeathType):
"""Instantiate a message with the given values."""
self.spaz = spaz
self.killed = was_killed
@@ -252,7 +252,8 @@ class PlayerSpaz(basespaz.Spaz):
if not self._dead:
# Immediate-mode or left-game deaths don't count as 'kills'.
- killed = (not msg.immediate and msg.how != 'leftGame')
+ killed = (not msg.immediate
+ and msg.how is not ba.DeathType.LEFT_GAME)
activity = self._activity()
diff --git a/assets/src/ba_data/python/bastd/actor/popuptext.py b/assets/src/ba_data/python/bastd/actor/popuptext.py
index 370f84b2..134811fe 100644
--- a/assets/src/ba_data/python/bastd/actor/popuptext.py
+++ b/assets/src/ba_data/python/bastd/actor/popuptext.py
@@ -122,7 +122,7 @@ class PopupText(ba.Actor):
lifespan, ba.WeakCall(self.handlemessage, ba.DieMessage()))
def handlemessage(self, msg: Any) -> Any:
- if __debug__ is True:
+ if __debug__:
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage):
if self.node:
diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py
index 565bfa1b..1e38890b 100644
--- a/assets/src/ba_data/python/bastd/actor/spaz.py
+++ b/assets/src/ba_data/python/bastd/actor/spaz.py
@@ -128,8 +128,10 @@ class Spaz(ba.Actor):
else:
self._punch_power_scale = factory.punch_power_scale
self.fly = ba.sharedobj('globals').happy_thoughts_mode
- assert isinstance(activity, ba.GameActivity)
- self._hockey = activity.map.is_hockey
+ if isinstance(activity, ba.GameActivity):
+ self._hockey = activity.map.is_hockey
+ else:
+ self._hockey = False
self._punched_nodes: Set[ba.Node] = set()
self._cursed = False
self._connected_to_player: Optional[ba.Player] = None
@@ -588,11 +590,12 @@ class Spaz(ba.Actor):
def on_punched(self, damage: int) -> None:
"""Called when this spaz gets punched."""
- def get_death_points(self, how: str) -> Tuple[int, int]:
+ def get_death_points(self, how: ba.DeathType) -> Tuple[int, int]:
"""Get the points awarded for killing this spaz."""
- del how # unused arg
+ del how # Unused.
num_hits = float(max(1, self._num_times_hit))
- # base points is simply 10 for 1-hit-kills and 5 otherwise
+
+ # Base points is simply 10 for 1-hit-kills and 5 otherwise.
importance = 2 if num_hits < 2 else 1
return (10 if num_hits < 2 else 5) * self.points_mult, importance
@@ -604,7 +607,8 @@ class Spaz(ba.Actor):
if not self._cursed:
factory = get_factory()
self._cursed = True
- # add the curse material..
+
+ # Add the curse material.
for attr in ['materials', 'roller_materials']:
materials = getattr(self.node, attr)
if factory.curse_material not in materials:
@@ -616,7 +620,7 @@ class Spaz(ba.Actor):
if self.curse_time is None:
self.node.curse_death_time = -1
else:
- # note: curse-death-time takes milliseconds
+ # Note: curse-death-time takes milliseconds.
tval = ba.time()
assert isinstance(tval, int)
self.node.curse_death_time = int(1000.0 *
@@ -629,7 +633,7 @@ class Spaz(ba.Actor):
"""
assert self.node
self.node.boxing_gloves = True
- if self._demo_mode: # preserve old behavior
+ if self._demo_mode: # Preserve old behavior.
self._punch_power_scale = 1.7
self._punch_cooldown = 300
else:
@@ -664,7 +668,7 @@ class Spaz(ba.Actor):
self.shield_decay_timer = ba.Timer(0.5,
ba.WeakCall(self.shield_decay),
repeat=True)
- # so user can see the decay
+ # So user can see the decay.
self.shield.always_show_health_bar = True
def shield_decay(self) -> None:
@@ -691,24 +695,25 @@ class Spaz(ba.Actor):
# pylint: disable=too-many-return-statements
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
- if __debug__ is True:
+ if __debug__:
self._handlemessage_sanity_check()
if isinstance(msg, ba.PickedUpMessage):
if self.node:
self.node.handlemessage("hurt_sound")
self.node.handlemessage("picked_up")
- # this counts as a hit
+
+ # This counts as a hit.
self._num_times_hit += 1
elif isinstance(msg, ba.ShouldShatterMessage):
- # eww; seems we have to do this in a timer or it wont work right
+ # Eww; seems we have to do this in a timer or it wont work right.
# (since we're getting called from within update() perhaps?..)
- # NOTE: should test to see if that's still the case
+ # NOTE: should test to see if that's still the case.
ba.timer(0.001, ba.WeakCall(self.shatter))
elif isinstance(msg, ba.ImpactDamageMessage):
- # eww; seems we have to do this in a timer or it wont work right
+ # Eww; seems we have to do this in a timer or it wont work right.
# (since we're getting called from within update() perhaps?..)
ba.timer(0.001, ba.WeakCall(self._hit_self, msg.intensity))
@@ -799,7 +804,8 @@ class Spaz(ba.Actor):
timeformat=ba.TimeFormat.MILLISECONDS))
elif msg.poweruptype == 'shield':
factory = get_factory()
- # let's allow powerup-equipped shields to lose hp over time
+
+ # Let's allow powerup-equipped shields to lose hp over time.
self.equip_shields(decay=factory.shield_decay_rate > 0)
elif msg.poweruptype == 'curse':
self.curse()
@@ -825,7 +831,8 @@ class Spaz(ba.Actor):
elif msg.poweruptype == 'health':
if self._cursed:
self._cursed = False
- # remove cursed material
+
+ # Remove cursed material.
factory = get_factory()
for attr in ['materials', 'roller_materials']:
materials = getattr(self.node, attr)
@@ -861,7 +868,7 @@ class Spaz(ba.Actor):
self.node.frozen = True
ba.timer(5.0, ba.WeakCall(self.handlemessage,
ba.ThawMessage()))
- # instantly shatter if we're already dead
+ # Instantly shatter if we're already dead.
# (otherwise its hard to tell we're dead)
if self.hitpoints <= 0:
self.shatter()
@@ -880,7 +887,7 @@ class Spaz(ba.Actor):
position=self.node.position)
return True
- # if we were recently hit, don't count this as another
+ # If we were recently hit, don't count this as another.
# (so punch flurries and bomb pileups essentially count as 1 hit)
local_time = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
assert isinstance(local_time, int)
@@ -893,13 +900,13 @@ class Spaz(ba.Actor):
velocity_mag = msg.velocity_magnitude * self.impact_scale
damage_scale = 0.22
- # if they've got a shield, deliver it to that instead..
+ # If they've got a shield, deliver it to that instead.
if self.shield:
if msg.flat_damage:
damage = msg.flat_damage * self.impact_scale
else:
- # hit our spaz with an impulse but tell it to only return
- # theoretical damage; not apply the impulse..
+ # Hit our spaz with an impulse but tell it to only return
+ # theoretical damage; not apply the impulse.
assert msg.force_direction is not None
self.node.handlemessage(
"impulse", msg.pos[0], msg.pos[1], msg.pos[2],
@@ -1086,7 +1093,8 @@ class Spaz(ba.Actor):
if self.frozen and (damage > 200 or self.hitpoints <= 0):
self.shatter()
elif self.hitpoints <= 0:
- self.node.handlemessage(ba.DieMessage(how='impact'))
+ self.node.handlemessage(
+ ba.DieMessage(how=ba.DeathType.IMPACT))
# if we're dead, take a look at the smoothed damage val
# (which gives us a smoothed average of recent damage) and shatter
@@ -1114,8 +1122,9 @@ class Spaz(ba.Actor):
ba.timer(2.0, self.node.delete)
elif isinstance(msg, ba.OutOfBoundsMessage):
- # by default we just die here
- self.handlemessage(ba.DieMessage(how='fall'))
+ # By default we just die here.
+ self.handlemessage(ba.DieMessage(how=ba.DeathType.FALL))
+
elif isinstance(msg, ba.StandMessage):
self._last_stand_pos = (msg.position[0], msg.position[1],
msg.position[2])
@@ -1123,8 +1132,10 @@ class Spaz(ba.Actor):
self.node.handlemessage("stand", msg.position[0],
msg.position[1], msg.position[2],
msg.angle)
+
elif isinstance(msg, CurseExplodeMessage):
self.curse_explode()
+
elif isinstance(msg, PunchHitMessage):
if not self.node:
return None
diff --git a/assets/src/ba_data/python/bastd/actor/spazbot.py b/assets/src/ba_data/python/bastd/actor/spazbot.py
index cc5ea5fb..a5eee8b9 100644
--- a/assets/src/ba_data/python/bastd/actor/spazbot.py
+++ b/assets/src/ba_data/python/bastd/actor/spazbot.py
@@ -80,7 +80,7 @@ class SpazBotDeathMessage:
"""
def __init__(self, badguy: SpazBot, killerplayer: Optional[ba.Player],
- how: str):
+ how: ba.DeathType):
"""Instantiate with given values."""
self.badguy = badguy
self.killerplayer = killerplayer
@@ -111,9 +111,9 @@ class SpazBot(basespaz.Spaz):
static = False
bouncy = False
run = False
- charge_dist_min = 0.0 # when we can start a new charge
- charge_dist_max = 2.0 # when we can start a new charge
- run_dist_min = 0.0 # how close we can be to continue running
+ charge_dist_min = 0.0 # When we can start a new charge.
+ charge_dist_max = 2.0 # When we can start a new charge.
+ run_dist_min = 0.0 # How close we can be to continue running.
charge_speed_min = 0.4
charge_speed_max = 1.0
throw_dist_min = 5.0
@@ -193,6 +193,7 @@ class SpazBot(basespaz.Spaz):
assert self._player_pts
for plpt, plvel in self._player_pts:
dist = (plpt - botpt).length()
+
# Ignore player-points that are significantly below the bot
# (keeps bots from following players off cliffs).
if (closest_dist is None
@@ -218,9 +219,12 @@ class SpazBot(basespaz.Spaz):
# pylint: disable=too-many-locals
if self.update_callback is not None:
if self.update_callback(self):
- return # true means bot has been handled
+ # Bot has been handled.
+ return
+
+ if not self.node:
+ return
- assert self.node
pos = self.node.position
our_pos = ba.Vec3(pos[0], 0, pos[2])
can_attack = True
@@ -239,11 +243,13 @@ class SpazBot(basespaz.Spaz):
holding_flag = False
else:
holding_flag = False
+
# If we're holding the flag, just walk left.
if holding_flag:
- # just walk left
+ # Just walk left.
self.node.move_left_right = -1.0
self.node.move_up_down = 0.0
+
# Otherwise try to go pick it up.
else:
assert self.target_flag.node
@@ -273,6 +279,7 @@ class SpazBot(basespaz.Spaz):
self.node.pickup_pressed = True
self.node.pickup_pressed = False
return
+
# Not a flag-bearer. If we're holding anything but a bomb, drop it.
if self.node.hold_node:
try:
@@ -289,12 +296,13 @@ class SpazBot(basespaz.Spaz):
target_pt_raw, target_vel = self._get_target_player_pt()
if target_pt_raw is None:
- # use default target if we've got one
+ # Use default target if we've got one.
if self.target_point_default is not None:
target_pt_raw = self.target_point_default
target_vel = ba.Vec3(0, 0, 0)
can_attack = False
- # with no target, we stop moving and drop whatever we're holding
+
+ # With no target, we stop moving and drop whatever we're holding.
else:
self.node.move_left_right = 0
self.node.move_up_down = 0
@@ -303,13 +311,14 @@ class SpazBot(basespaz.Spaz):
self.node.pickup_pressed = False
return
- # we don't want height to come into play
+ # We don't want height to come into play.
target_pt_raw[1] = 0.0
assert target_vel is not None
target_vel[1] = 0.0
dist_raw = (target_pt_raw - our_pos).length()
- # use a point out in front of them as real target
+
+ # Use a point out in front of them as real target.
# (more out in front the farther from us they are)
target_pt = (target_pt_raw +
target_vel * dist_raw * 0.3 * self._lead_amount)
@@ -319,25 +328,26 @@ class SpazBot(basespaz.Spaz):
to_target = diff.normalized()
if self._mode == 'throw':
- # we can only throw if alive and well..
+ # We can only throw if alive and well.
if not self._dead and not self.node.knockout:
assert self._throw_release_time is not None
time_till_throw = self._throw_release_time - ba.time()
if not self.node.hold_node:
- # if we haven't thrown yet, whip out the bomb
+ # If we haven't thrown yet, whip out the bomb.
if not self._have_dropped_throw_bomb:
self.drop_bomb()
self._have_dropped_throw_bomb = True
- # otherwise our lack of held node means we successfully
- # released our bomb.. lets retreat now
+
+ # Otherwise our lack of held node means we successfully
+ # released our bomb; lets retreat now.
else:
self._mode = 'flee'
- # oh crap we're holding a bomb.. better throw it.
+ # Oh crap, we're holding a bomb; better throw it.
elif time_till_throw <= 0.0:
- # jump and throw..
+ # Jump and throw.
def _safe_pickup(node: ba.Node) -> None:
if node and self.node:
self.node.pickup_pressed = True
@@ -346,25 +356,26 @@ class SpazBot(basespaz.Spaz):
if dist > 5.0:
self.node.jump_pressed = True
self.node.jump_pressed = False
- # throws:
+
+ # Throws:
ba.timer(0.1, ba.Call(_safe_pickup, self.node))
else:
- # throws:
+ # Throws:
ba.timer(0.1, ba.Call(_safe_pickup, self.node))
if self.static:
if time_till_throw < 0.3:
speed = 1.0
elif time_till_throw < 0.7 and dist > 3.0:
- speed = -1.0 # whiplash for long throws
+ speed = -1.0 # Whiplash for long throws.
else:
speed = 0.02
else:
if time_till_throw < 0.7:
- # right before throw charge full speed towards target
+ # Right before throw charge full speed towards target.
speed = 1.0
else:
- # earlier we can hold or move backward for a whiplash
+ # Earlier we can hold or move backward for a whiplash.
speed = 0.0125
self.node.move_left_right = to_target.x * speed
self.node.move_up_down = to_target.z * -1.0 * speed
@@ -373,8 +384,9 @@ class SpazBot(basespaz.Spaz):
if random.random() < 0.3:
self._charge_speed = random.uniform(self.charge_speed_min,
self.charge_speed_max)
- # if we're a runner we run during charges *except when near
- # an edge (otherwise we tend to fly off easily)
+
+ # If we're a runner we run during charges *except when near
+ # an edge (otherwise we tend to fly off easily).
if self.run and dist_raw > self.run_dist_min:
self._lead_amount = 0.3
self._running = True
@@ -388,8 +400,8 @@ class SpazBot(basespaz.Spaz):
self.node.move_up_down = to_target.z * -1.0 * self._charge_speed
elif self._mode == 'wait':
- # every now and then, aim towards our target..
- # other than that, just stand there
+ # Every now and then, aim towards our target.
+ # Other than that, just stand there.
if ba.time(timeformat=ba.TimeFormat.MILLISECONDS) % 1234 < 100:
self.node.move_left_right = to_target.x * (400.0 / 33000)
self.node.move_up_down = to_target.z * (-400.0 / 33000)
@@ -398,8 +410,8 @@ class SpazBot(basespaz.Spaz):
self.node.move_up_down = 0
elif self._mode == 'flee':
- # even if we're a runner, only run till we get away from our
- # target (if we keep running we tend to run off edges)
+ # Even if we're a runner, only run till we get away from our
+ # target (if we keep running we tend to run off edges).
if self.run and dist < 3.0:
self._running = True
self.node.run = 1.0
@@ -409,20 +421,20 @@ class SpazBot(basespaz.Spaz):
self.node.move_left_right = to_target.x * -1.0
self.node.move_up_down = to_target.z
- # we might wanna switch states unless we're doing a throw
- # (in which case that's our sole concern)
+ # We might wanna switch states unless we're doing a throw
+ # (in which case that's our sole concern).
if self._mode != 'throw':
- # if we're currently charging, keep track of how far we are
- # from our target.. when this value increases it means our charge
- # is over (ran by them or something)
+ # If we're currently charging, keep track of how far we are
+ # from our target. When this value increases it means our charge
+ # is over (ran by them or something).
if self._mode == 'charge':
if (self._charge_closing_in
and self._last_charge_dist < dist < 3.0):
self._charge_closing_in = False
self._last_charge_dist = dist
- # if we have a clean shot, throw!
+ # If we have a clean shot, throw!
if (self.throw_dist_min <= dist < self.throw_dist_max
and random.random() < self.throwiness and can_attack):
self._mode = 'throw'
@@ -434,15 +446,15 @@ class SpazBot(basespaz.Spaz):
(1.0 / self.throw_rate) *
(0.8 + 1.3 * random.random()))
- # if we're static, always charge (which for us means barely move)
+ # If we're static, always charge (which for us means barely move).
elif self.static:
self._mode = 'wait'
- # if we're too close to charge (and aren't in the middle of an
- # existing charge) run away
+ # If we're too close to charge (and aren't in the middle of an
+ # existing charge) run away.
elif dist < self.charge_dist_min and not self._charge_closing_in:
- # ..unless we're near an edge, in which case we got no choice
- # but to charge..
+ # ..unless we're near an edge, in which case we've got no
+ # choice but to charge.
if self.map.is_point_near_edge(our_pos, self._running):
if self._mode != 'charge':
self._mode = 'charge'
@@ -452,7 +464,7 @@ class SpazBot(basespaz.Spaz):
else:
self._mode = 'flee'
- # we're within charging distance, backed against an edge,
+ # We're within charging distance, backed against an edge,
# or farther than our max throw distance.. chaaarge!
elif (dist < self.charge_dist_max or dist > self.throw_dist_max
or self.map.is_point_near_edge(our_pos, self._running)):
@@ -462,11 +474,11 @@ class SpazBot(basespaz.Spaz):
self._charge_closing_in = True
self._last_charge_dist = dist
- # we're too close to throw but too far to charge - either run
- # away or just chill if we're near an edge
+ # We're too close to throw but too far to charge - either run
+ # away or just chill if we're near an edge.
elif dist < self.throw_dist_min:
- # charge if either we're within charge range or
- # cant retreat to throw
+ # Charge if either we're within charge range or
+ # cant retreat to throw.
self._mode = 'flee'
# Do some awesome jumps if we're running.
@@ -494,29 +506,30 @@ class SpazBot(basespaz.Spaz):
def on_expire(self) -> None:
basespaz.Spaz.on_expire(self)
- # we're being torn down; release
- # our callback(s) so there's no chance of them
- # keeping activities or other things alive..
+
+ # We're being torn down; release our callback(s) so there's
+ # no chance of them keeping activities or other things alive.
self.update_callback = None
def handlemessage(self, msg: Any) -> Any:
# pylint: disable=too-many-branches
self._handlemessage_sanity_check()
- # keep track of if we're being held and by who most recently
+ # Keep track of if we're being held and by who most recently.
if isinstance(msg, ba.PickedUpMessage):
- super().handlemessage(msg) # augment standard behavior
+ super().handlemessage(msg) # Augment standard behavior.
self.held_count += 1
picked_up_by = msg.node.source_player
if picked_up_by:
self.last_player_held_by = picked_up_by
elif isinstance(msg, ba.DroppedMessage):
- super().handlemessage(msg) # augment standard behavior
+ super().handlemessage(msg) # Augment standard behavior.
self.held_count -= 1
if self.held_count < 0:
print("ERROR: spaz held_count < 0")
- # let's count someone dropping us as an attack..
+
+ # Let's count someone dropping us as an attack.
try:
if msg.node:
picked_up_by = msg.node.source_player
@@ -533,18 +546,19 @@ class SpazBot(basespaz.Spaz):
elif isinstance(msg, ba.DieMessage):
- # report normal deaths for scoring purposes
+ # Report normal deaths for scoring purposes.
if not self._dead and not msg.immediate:
killerplayer: Optional[ba.Player]
- # if this guy was being held at the time of death, the
- # holder is the killer
+
+ # If this guy was being held at the time of death, the
+ # holder is the killer.
if self.held_count > 0 and self.last_player_held_by:
killerplayer = self.last_player_held_by
else:
- # otherwise if they were attacked by someone in the
- # last few seconds that person's the killer..
- # otherwise it was a suicide
+ # If they were attacked by someone in the last few
+ # seconds that person's the killer.
+ # Otherwise it was a suicide.
if (self.last_player_attacked_by
and ba.time() - self.last_attacked_time < 4.0):
killerplayer = self.last_player_attacked_by
@@ -552,15 +566,15 @@ class SpazBot(basespaz.Spaz):
killerplayer = None
activity = self._activity()
- # (convert dead refs to None)
+ # (convert dead player refs to None)
if not killerplayer:
killerplayer = None
if activity is not None:
activity.handlemessage(
SpazBotDeathMessage(self, killerplayer, msg.how))
- super().handlemessage(msg) # augment standard behavior
+ super().handlemessage(msg) # Augment standard behavior.
- # keep track of the player who last hit us for point rewarding
+ # Keep track of the player who last hit us for point rewarding.
elif isinstance(msg, ba.HitMessage):
if msg.source_player:
self.last_player_attacked_by = msg.source_player
@@ -889,8 +903,9 @@ class BotSet:
def __init__(self) -> None:
"""Create a bot-set."""
- # we spread our bots out over a few lists so we can update
- # them in a staggered fashion
+
+ # We spread our bots out over a few lists so we can update
+ # them in a staggered fashion.
self._bot_list_count = 5
self._bot_add_list = 0
self._bot_update_list = 0
@@ -963,7 +978,7 @@ class BotSet:
self._bot_update_list = (self._bot_update_list +
1) % self._bot_list_count
- # update our list of player points for the bots to use
+ # Update our list of player points for the bots to use.
player_pts = []
for player in ba.getactivity().players:
try:
@@ -980,7 +995,8 @@ class BotSet:
def clear(self) -> None:
"""Immediately clear out any bots in the set."""
- # don't do this if the activity is shutting down or dead
+
+ # Don't do this if the activity is shutting down or dead.
activity = ba.getactivity(doraise=False)
if activity is None or activity.is_expired():
return
@@ -1025,7 +1041,8 @@ class BotSet:
Use this when the bots have won a game.
"""
self._bot_update_timer = None
- # at this point stop doing anything but jumping and celebrating
+
+ # At this point stop doing anything but jumping and celebrating.
for botlist in self._bot_lists:
for bot in botlist:
if bot.node:
diff --git a/assets/src/ba_data/python/bastd/actor/text.py b/assets/src/ba_data/python/bastd/actor/text.py
index 8e64e4d6..3004cbd7 100644
--- a/assets/src/ba_data/python/bastd/actor/text.py
+++ b/assets/src/ba_data/python/bastd/actor/text.py
@@ -191,7 +191,7 @@ class Text(ba.Actor):
ba.WeakCall(self.handlemessage, ba.DieMessage()))
def handlemessage(self, msg: Any) -> Any:
- if __debug__ is True:
+ if __debug__:
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage):
if self.node:
diff --git a/assets/src/ba_data/python/bastd/actor/tipstext.py b/assets/src/ba_data/python/bastd/actor/tipstext.py
index 4a3883ca..5b98f39e 100644
--- a/assets/src/ba_data/python/bastd/actor/tipstext.py
+++ b/assets/src/ba_data/python/bastd/actor/tipstext.py
@@ -103,7 +103,7 @@ class TipsText(ba.Actor):
self.node.text = next_tip
def handlemessage(self, msg: Any) -> Any:
- if __debug__ is True:
+ if __debug__:
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage):
if self.node:
diff --git a/assets/src/ba_data/python/bastd/actor/zoomtext.py b/assets/src/ba_data/python/bastd/actor/zoomtext.py
index f2184b75..f2fedf3a 100644
--- a/assets/src/ba_data/python/bastd/actor/zoomtext.py
+++ b/assets/src/ba_data/python/bastd/actor/zoomtext.py
@@ -171,7 +171,7 @@ class ZoomText(ba.Actor):
ba.DieMessage()))
def handlemessage(self, msg: Any) -> Any:
- if __debug__ is True:
+ if __debug__:
self._handlemessage_sanity_check()
if isinstance(msg, ba.DieMessage):
if not self._dying and self.node:
diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py
index d515dd2d..4d0abeeb 100644
--- a/assets/src/ba_data/python/bastd/game/easteregghunt.py
+++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py
@@ -213,7 +213,7 @@ class EasterEggHuntGame(ba.TeamGameActivity):
player = msg.spaz.getplayer()
if not player:
return
- self.stats.player_lost_spaz(player)
+ self.stats.player_was_killed(player)
# Respawn them shortly.
assert self.initial_player_info is not None
diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py
index b600eeb9..3f814cb9 100644
--- a/assets/src/ba_data/python/bastd/game/football.py
+++ b/assets/src/ba_data/python/bastd/game/football.py
@@ -814,7 +814,7 @@ class FootballCoopGame(ba.CoopGameActivity):
# Respawn dead players.
player = msg.spaz.player
- self.stats.player_lost_spaz(player)
+ self.stats.player_was_killed(player)
assert self.initial_player_info is not None
respawn_time = 2.0 + len(self.initial_player_info) * 1.0
diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py
index d0dbf2f3..07eea612 100644
--- a/assets/src/ba_data/python/bastd/game/runaround.py
+++ b/assets/src/ba_data/python/bastd/game/runaround.py
@@ -415,7 +415,8 @@ class RunaroundGame(ba.CoopGameActivity):
})
ba.animate(light, 'intensity', {0.0: 0, 0.1: 1, 0.5: 0}, loop=False)
ba.timer(1.0, light.delete)
- spaz.handlemessage(ba.DieMessage(immediate=True, how='goal'))
+ spaz.handlemessage(
+ ba.DieMessage(immediate=True, how=ba.DeathType.REACHED_GOAL))
if self._lives > 0:
self._lives -= 1
@@ -1130,7 +1131,7 @@ class RunaroundGame(ba.CoopGameActivity):
return
if not player:
return
- self.stats.player_lost_spaz(player)
+ self.stats.player_was_killed(player)
# Respawn them shortly.
assert self.initial_player_info is not None
@@ -1141,7 +1142,7 @@ class RunaroundGame(ba.CoopGameActivity):
player, respawn_time)
elif isinstance(msg, spazbot.SpazBotDeathMessage):
- if msg.how == 'goal':
+ if msg.how is ba.DeathType.REACHED_GOAL:
return
pts, importance = msg.badguy.get_death_points(msg.how)
if msg.killerplayer is not None:
diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py
index 97efe353..340d8c33 100644
--- a/assets/src/ba_data/python/bastd/game/thelaststand.py
+++ b/assets/src/ba_data/python/bastd/game/thelaststand.py
@@ -263,7 +263,7 @@ class TheLastStandGame(ba.CoopGameActivity):
return
if not player:
return
- self.stats.player_lost_spaz(player)
+ self.stats.player_was_killed(player)
ba.timer(0.1, self._checkroundover)
elif isinstance(msg, ba.PlayerScoredMessage):
diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py
index 491bc6c4..902fcd02 100644
--- a/assets/src/ba_data/python/bastd/ui/coop/browser.py
+++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py
@@ -61,7 +61,7 @@ class CoopBrowserWindow(ba.Window):
app = ba.app
cfg = app.config
- # if they provided an origin-widget, scale up from that
+ # If they provided an origin-widget, scale up from that.
scale_origin: Optional[Tuple[float, float]]
if origin_widget is not None:
self._transition_out = 'out_scale'
@@ -71,8 +71,8 @@ class CoopBrowserWindow(ba.Window):
self._transition_out = 'out_right'
scale_origin = None
- # try to recreate the same number of buttons we had last time so our
- # re-selection code works
+ # Try to recreate the same number of buttons we had last time so our
+ # re-selection code works.
try:
self._tournament_button_count = app.config['Tournament Rows']
except Exception:
@@ -159,7 +159,7 @@ class CoopBrowserWindow(ba.Window):
self._store_button_widget = None
self._league_rank_button_widget = None
- # move our corner buttons dynamically to keep them out of the way of
+ # Move our corner buttons dynamically to keep them out of the way of
# the party icon :-(
self._update_corner_button_positions()
self._update_corner_button_positions_timer = ba.Timer(
@@ -179,7 +179,7 @@ class CoopBrowserWindow(ba.Window):
self._selected_challenge_level = (cfg.get(
'Selected Coop Challenge Level', None))
- # Don't want initial construction affecting our last-selected
+ # Don't want initial construction affecting our last-selected.
self._do_selection_callbacks = False
v = self._height - 95
txt = ba.textwidget(
@@ -229,22 +229,23 @@ class CoopBrowserWindow(ba.Window):
simple_culling_v=10.0)
self._subcontainer: Optional[ba.Widget] = None
- # take note of our account state; we'll refresh later if this changes
+ # Take note of our account state; we'll refresh later if this changes.
self._account_state_num = _ba.get_account_state_num()
- # same for fg/bg state..
+
+ # Same for fg/bg state.
self._fg_state = app.fg_state
self._refresh()
self._restore_state()
- # even though we might display cached tournament data immediately, we
- # don't consider it valid until we've pinged
+ # Even though we might display cached tournament data immediately, we
+ # don't consider it valid until we've pinged.
# the server for an update
self._tourney_data_up_to_date = False
- # if we've got a cached tournament list for our account and info for
- # each one of those tournaments,
- # go ahead and display it as a starting point...
+ # If we've got a cached tournament list for our account and info for
+ # each one of those tournaments, go ahead and display it as a
+ # starting point.
if (app.account_tournament_list is not None and
app.account_tournament_list[0] == _ba.get_account_state_num()
and all([
@@ -257,7 +258,7 @@ class CoopBrowserWindow(ba.Window):
]
self._update_for_data(tourney_data)
- # this will pull new data periodically, update timers, etc..
+ # This will pull new data periodically, update timers, etc.
self._update_timer = ba.Timer(1.0,
ba.WeakCall(self._update),
timetype=ba.TimeType.REAL,
@@ -267,31 +268,32 @@ class CoopBrowserWindow(ba.Window):
def _update(self) -> None:
cur_time = ba.time(ba.TimeType.REAL)
- # if its been a while since we got a tournament update, consider the
+ # If its been a while since we got a tournament update, consider the
# data invalid (prevents us from joining tournaments if our internet
- # connection goes down for a while)
+ # connection goes down for a while).
if (self._last_tournament_query_response_time is None
or ba.time(ba.TimeType.REAL) -
self._last_tournament_query_response_time > 60.0 * 2):
self._tourney_data_up_to_date = False
- # if our account state has changed, do a full request
+ # If our account state has changed, do a full request.
account_state_num = _ba.get_account_state_num()
if account_state_num != self._account_state_num:
self._account_state_num = account_state_num
self._save_state()
self._refresh()
- # also encourage a new tournament query since this will clear out
- # our current results..
+
+ # Also encourage a new tournament query since this will clear out
+ # our current results.
if not self._doing_tournament_query:
self._last_tournament_query_time = None
- # if we've been backgrounded/foregrounded, invalidate our
- # tournament entries (they will be refreshed below asap)
+ # If we've been backgrounded/foregrounded, invalidate our
+ # tournament entries (they will be refreshed below asap).
if self._fg_state != ba.app.fg_state:
self._tourney_data_up_to_date = False
- # send off a new tournament query if its been long enough or whatnot..
+ # Send off a new tournament query if its been long enough or whatnot.
if not self._doing_tournament_query and (
self._last_tournament_query_time is None
or cur_time - self._last_tournament_query_time > 30.0
@@ -299,24 +301,28 @@ class CoopBrowserWindow(ba.Window):
self._fg_state = ba.app.fg_state
self._last_tournament_query_time = cur_time
self._doing_tournament_query = True
- _ba.tournament_query(args={
- 'source': 'coop window refresh',
- 'numScores': 1
- },
- callback=ba.WeakCall(
- self._on_tournament_query_response))
+ _ba.tournament_query(
+ args={
+ 'source': 'coop window refresh',
+ 'numScores': 1
+ },
+ callback=ba.WeakCall(self._on_tournament_query_response),
+ )
- # decrement time on our tournament buttons..
+ # Decrement time on our tournament buttons.
ads_enabled = _ba.have_incentivized_ad()
for tbtn in self._tournament_buttons:
tbtn['time_remaining'] = max(0, tbtn['time_remaining'] - 1)
if tbtn['time_remaining_value_text'] is not None:
ba.textwidget(
edit=tbtn['time_remaining_value_text'],
- text=ba.timestring(tbtn['time_remaining'], centi=False) if
+ text=ba.timestring(tbtn['time_remaining'],
+ centi=False,
+ suppress_format_warning=True) if
(tbtn['has_time_remaining']
and self._tourney_data_up_to_date) else '-')
- # also adjust the ad icon visibility
+
+ # Also adjust the ad icon visibility.
if tbtn.get('allow_ads', False) and _ba.has_video_ads():
ba.imagewidget(edit=tbtn['entry_fee_ad_image'],
opacity=1.0 if ads_enabled else 0.25)
@@ -427,7 +433,8 @@ class CoopBrowserWindow(ba.Window):
leader_score = (
ba.timestring(score[0] * 10,
centi=True,
- timeformat=ba.TimeFormat.MILLISECONDS)
+ timeformat=ba.TimeFormat.MILLISECONDS,
+ suppress_format_warning=True)
if entry['scoreType'] == 'time' else str(score[0]))
else:
tbtn['leader'] = None
@@ -445,7 +452,9 @@ class CoopBrowserWindow(ba.Window):
'-' if entry is None or 'totalTime' not in entry else ba.Lstr(
resource=self._r + '.ofTotalTimeText',
subs=[('${TOTAL}',
- ba.timestring(entry['totalTime'], centi=False))]))
+ ba.timestring(entry['totalTime'],
+ centi=False,
+ suppress_format_warning=True))]))
ba.textwidget(edit=tbtn['time_remaining_out_of_text'],
text=out_of_time_text)
@@ -516,18 +525,14 @@ class CoopBrowserWindow(ba.Window):
final_fee_str = (
ba.charstr(ba.SpecialChar.TICKET_BACKING) +
str(final_fee))
- # final_fee_str: Union[str, ba.Lstr] = (
- # '' if fee_var is None else ba.Lstr(
- # resource='getTicketsWindow.freeText') if final_fee == 0
- # else (ba.specialchar('ticket_backing') + str(final_fee)))
ad_tries_remaining = ba.app.tournament_info[
tbtn['tournament_id']]['adTriesRemaining']
free_tries_remaining = ba.app.tournament_info[
tbtn['tournament_id']]['freeTriesRemaining']
- # now, if this fee allows ads and we support video ads, show
- # the 'or ad' version
+ # Now, if this fee allows ads and we support video ads, show
+ # the 'or ad' version.
if allow_ads and _ba.has_video_ads():
ads_enabled = _ba.have_incentivized_ad()
ba.imagewidget(edit=tbtn['entry_fee_ad_image'],
@@ -542,7 +547,8 @@ class CoopBrowserWindow(ba.Window):
tbtn['button_y'] + tbtn['button_scale_y'] - 60),
scale=1.3,
text=final_fee_str)
- # possibly show number of ad-plays remaining
+
+ # Possibly show number of ad-plays remaining.
ba.textwidget(
edit=tbtn['entry_fee_text_remaining'],
position=(tbtn['button_x'] + 360,
@@ -559,7 +565,8 @@ class CoopBrowserWindow(ba.Window):
tbtn['button_y'] + tbtn['button_scale_y'] - 80),
scale=1.3,
text=final_fee_str)
- # possibly show number of free-plays remaining
+
+ # Possibly show number of free-plays remaining.
ba.textwidget(
edit=tbtn['entry_fee_text_remaining'],
position=(tbtn['button_x'] + 360,
@@ -927,15 +934,8 @@ class CoopBrowserWindow(ba.Window):
'Challenges:Meteor Shower',
'Challenges:Target Practice B',
'Challenges:Target Practice',
- # 'Challenges:Lake Frigid Race',
- # 'Challenges:Uber Runaround',
- # 'Challenges:Runaround',
- # 'Challenges:Pro Race',
- # 'Challenges:Pro Football',
- # 'Challenges:Epic Meteor Shower',
- # 'Challenges:Testing',
- # 'User:Ninja Fight',
]
+
# Show easter-egg-hunt either if its easter or we own it.
if _ba.get_account_misc_read_val(
'easter', False) or _ba.get_purchased('games.easter_egg_hunt'):
@@ -1456,7 +1456,7 @@ class CoopBrowserWindow(ba.Window):
ba.playsound(ba.getsound('error'))
return
- # game is whatever the tournament tells us it is
+ # Game is whatever the tournament tells us it is.
game = ba.app.tournament_info[
tournament_button['tournament_id']]['game']
@@ -1469,7 +1469,7 @@ class CoopBrowserWindow(ba.Window):
height=130)
return
- # infinite onslaught/runaround require pro; bring up a store link if
+ # Infinite onslaught/runaround require pro; bring up a store link if
# need be.
if tournament_button is None and game in (
'Challenges:Infinite Runaround',
diff --git a/assets/src/ba_data/python/efro/entity/_field.py b/assets/src/ba_data/python/efro/entity/_field.py
index 1dc273c5..d0791186 100644
--- a/assets/src/ba_data/python/efro/entity/_field.py
+++ b/assets/src/ba_data/python/efro/entity/_field.py
@@ -96,7 +96,7 @@ class CompoundField(BaseField, Generic[TC]):
value: TC,
store_default: bool = True) -> None:
super().__init__(d_key)
- if __debug__ is True:
+ if __debug__:
from efro.entity._value import CompoundValue
assert isinstance(value, CompoundValue)
assert not hasattr(value, 'd_data')
diff --git a/docs/ba_module.md b/docs/ba_module.md
index 9d798d85..8760c93a 100644
--- a/docs/ba_module.md
+++ b/docs/ba_module.md
@@ -1,5 +1,5 @@
-last updated on 2020-04-05 for Ballistica version 1.5.0 build 20001
+last updated on 2020-04-06 for Ballistica version 1.5.0 build 20001
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 let me know . Happy modding!
@@ -165,6 +165,7 @@
+inherits from: enum.Enum
+A reason for a death.
+
+Category: Enums
+
+
+Values:
+
+GENERIC
+IMPACT
+FALL
+REACHED_GOAL
+LEFT_GAME
+
+
inherits from: typing.Generic
A dependency on a DependencyComponent (with an optional config).
@@ -1747,9 +1764,8 @@ Exception types on other errors).
-str
-The particular reason for death; 'fall', 'impact', 'leftGame', etc.
-This can be examined for scoring or other purposes.
+DeathType
+The particular reason for death.
@@ -1764,7 +1780,7 @@ its time with lingering corpses, sound effects, etc.
Methods:
-ba.DieMessage(immediate: 'bool' = False, how: 'str' = 'generic')
+ba.DieMessage(immediate: bool = False, how: DeathType = <DeathType.GENERIC: generic>)
@@ -3666,7 +3682,7 @@ other players.
Methods:
-
+
ba.PlayerRecord(name: str, name_full: str, player: ba.Player , stats: ba.Stats )
@@ -3701,12 +3717,6 @@ other players.
Return the player entry's name.
-
-
-get_spaz(self) -> Optional[ba.Actor ]
-
-Return the player entry's spaz.
-
getactivity(self) -> Optional[ba.Activity ]
@@ -4145,7 +4155,7 @@ session.set_activity(foo) and then ba.newnode
Methods:
-
+
ba.Stats()
@@ -4170,18 +4180,6 @@ session.set_activity(foo) and then ba.newnode
Call this when a player got hit.
-
-
-player_got_new_spaz(self, player: ba.Player , spaz: ba.Actor ) -> None
-
-Call this when a player gets a new Spaz.
-
-
-
-player_lost_spaz(self, player: ba.Player , killed: bool = False, killer: ba.Player = None) -> None
-
-Should be called when a player loses a spaz.
-
player_scored(self, player: ba.Player , base_points: int = 1, target: Sequence[float] = None, kill: bool = False, victim_player: ba.Player = None, scale: float = 1.0, color: Sequence[float] = None, title: Union[str, ba.Lstr ] = None, screenmessage: bool = True, display: bool = True, importance: int = 1, showpoints: bool = True, big_message: bool = False) -> int
@@ -4190,6 +4188,12 @@ session.set_activity(foo) and then ba.newnode
Return value is actual score with multipliers and such factored in.
+
+
+player_was_killed(self, player: ba.Player , killed: bool = False, killer: ba.Player = None) -> None
+
+Should be called when a player is killed.
+
register_player(self, player: ba.Player ) -> None