mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-28 10:03:15 +08:00
Merge branch 'master' of https://github.com/efroemling/ballistica
This commit is contained in:
commit
c07aa0e357
@ -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"
|
||||
}
|
||||
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -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 * * *'
|
||||
|
||||
1
.idea/inspectionProfiles/Default.xml
generated
1
.idea/inspectionProfiles/Default.xml
generated
@ -48,6 +48,7 @@
|
||||
<scope name="UncheckedPython" level="WEAK WARNING" enabled="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyTypeCheckerInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PyUnreachableCodeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="PyIgnoreUnresolved" level="WARNING" enabled="false">
|
||||
<option name="ignoredIdentifiers">
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)),
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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')
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||
<h4><em>last updated on 2020-04-05 for Ballistica version 1.5.0 build 20001</em></h4>
|
||||
<h4><em>last updated on 2020-04-06 for Ballistica version 1.5.0 build 20001</em></h4>
|
||||
<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>
|
||||
<hr>
|
||||
@ -165,6 +165,7 @@
|
||||
</ul>
|
||||
<h4><a name="class_category_Enums">Enums</a></h4>
|
||||
<ul>
|
||||
<li><a href="#class_ba_DeathType">ba.DeathType</a></li>
|
||||
<li><a href="#class_ba_MusicPlayMode">ba.MusicPlayMode</a></li>
|
||||
<li><a href="#class_ba_MusicType">ba.MusicType</a></li>
|
||||
<li><a href="#class_ba_Permission">ba.Permission</a></li>
|
||||
@ -1575,6 +1576,22 @@ the data object is requested and when it's value is accessed.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_DeathType">ba.DeathType</a></strong></h3>
|
||||
<p>inherits from: enum.Enum</p>
|
||||
<p>A reason for a death.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Enums">Enums</a>
|
||||
</p>
|
||||
|
||||
<h3>Values:</h3>
|
||||
<ul>
|
||||
<li>GENERIC</li>
|
||||
<li>IMPACT</li>
|
||||
<li>FALL</li>
|
||||
<li>REACHED_GOAL</li>
|
||||
<li>LEFT_GAME</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_Dependency">ba.Dependency</a></strong></h3>
|
||||
<p>inherits from: <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>A dependency on a DependencyComponent (with an optional config).</p>
|
||||
@ -1747,9 +1764,8 @@ Exception types on other errors).</p>
|
||||
<h5><a href="#attr_ba_DieMessage__how">how</a>, <a href="#attr_ba_DieMessage__immediate">immediate</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_DieMessage__how">how</a></h4></dt><dd>
|
||||
<p><span>str</span></p>
|
||||
<p>The particular reason for death; 'fall', 'impact', 'leftGame', etc.
|
||||
This can be examined for scoring or other purposes.</p>
|
||||
<p><span>DeathType</span></p>
|
||||
<p>The particular reason for death.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_DieMessage__immediate">immediate</a></h4></dt><dd>
|
||||
@ -1764,7 +1780,7 @@ its time with lingering corpses, sound effects, etc.</p>
|
||||
<h3>Methods:</h3>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_DieMessage____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.DieMessage(immediate: 'bool' = False, how: 'str' = 'generic')</span></p>
|
||||
<p><span>ba.DieMessage(immediate: bool = False, how: DeathType = <DeathType.GENERIC: generic>)</span></p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
@ -3666,7 +3682,7 @@ other players.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_PlayerRecord____init__"><constructor></a>, <a href="#method_ba_PlayerRecord__associate_with_player">associate_with_player()</a>, <a href="#method_ba_PlayerRecord__cancel_multi_kill_timer">cancel_multi_kill_timer()</a>, <a href="#method_ba_PlayerRecord__get_icon">get_icon()</a>, <a href="#method_ba_PlayerRecord__get_last_player">get_last_player()</a>, <a href="#method_ba_PlayerRecord__get_name">get_name()</a>, <a href="#method_ba_PlayerRecord__get_spaz">get_spaz()</a>, <a href="#method_ba_PlayerRecord__getactivity">getactivity()</a>, <a href="#method_ba_PlayerRecord__submit_kill">submit_kill()</a></h5>
|
||||
<h5><a href="#method_ba_PlayerRecord____init__"><constructor></a>, <a href="#method_ba_PlayerRecord__associate_with_player">associate_with_player()</a>, <a href="#method_ba_PlayerRecord__cancel_multi_kill_timer">cancel_multi_kill_timer()</a>, <a href="#method_ba_PlayerRecord__get_icon">get_icon()</a>, <a href="#method_ba_PlayerRecord__get_last_player">get_last_player()</a>, <a href="#method_ba_PlayerRecord__get_name">get_name()</a>, <a href="#method_ba_PlayerRecord__getactivity">getactivity()</a>, <a href="#method_ba_PlayerRecord__submit_kill">submit_kill()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_PlayerRecord____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.PlayerRecord(name: str, name_full: str, player: <a href="#class_ba_Player">ba.Player</a>, stats: <a href="#class_ba_Stats">ba.Stats</a>)</span></p>
|
||||
@ -3701,12 +3717,6 @@ other players.</p>
|
||||
|
||||
<p>Return the player entry's name.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_PlayerRecord__get_spaz">get_spaz()</a></dt></h4><dd>
|
||||
<p><span>get_spaz(self) -> Optional[<a href="#class_ba_Actor">ba.Actor</a>]</span></p>
|
||||
|
||||
<p>Return the player entry's spaz.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_PlayerRecord__getactivity">getactivity()</a></dt></h4><dd>
|
||||
<p><span>getactivity(self) -> Optional[<a href="#class_ba_Activity">ba.Activity</a>]</span></p>
|
||||
@ -4145,7 +4155,7 @@ session.set_activity(foo) and then <a href="#function_ba_newnode">ba.newnode</a>
|
||||
</p>
|
||||
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_Stats____init__"><constructor></a>, <a href="#method_ba_Stats__get_records">get_records()</a>, <a href="#method_ba_Stats__getactivity">getactivity()</a>, <a href="#method_ba_Stats__player_got_hit">player_got_hit()</a>, <a href="#method_ba_Stats__player_got_new_spaz">player_got_new_spaz()</a>, <a href="#method_ba_Stats__player_lost_spaz">player_lost_spaz()</a>, <a href="#method_ba_Stats__player_scored">player_scored()</a>, <a href="#method_ba_Stats__register_player">register_player()</a>, <a href="#method_ba_Stats__reset">reset()</a>, <a href="#method_ba_Stats__reset_accum">reset_accum()</a>, <a href="#method_ba_Stats__set_activity">set_activity()</a></h5>
|
||||
<h5><a href="#method_ba_Stats____init__"><constructor></a>, <a href="#method_ba_Stats__get_records">get_records()</a>, <a href="#method_ba_Stats__getactivity">getactivity()</a>, <a href="#method_ba_Stats__player_got_hit">player_got_hit()</a>, <a href="#method_ba_Stats__player_scored">player_scored()</a>, <a href="#method_ba_Stats__player_was_killed">player_was_killed()</a>, <a href="#method_ba_Stats__register_player">register_player()</a>, <a href="#method_ba_Stats__reset">reset()</a>, <a href="#method_ba_Stats__reset_accum">reset_accum()</a>, <a href="#method_ba_Stats__set_activity">set_activity()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_Stats____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.Stats()</span></p>
|
||||
@ -4170,18 +4180,6 @@ session.set_activity(foo) and then <a href="#function_ba_newnode">ba.newnode</a>
|
||||
|
||||
<p>Call this when a player got hit.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Stats__player_got_new_spaz">player_got_new_spaz()</a></dt></h4><dd>
|
||||
<p><span>player_got_new_spaz(self, player: <a href="#class_ba_Player">ba.Player</a>, spaz: <a href="#class_ba_Actor">ba.Actor</a>) -> None</span></p>
|
||||
|
||||
<p>Call this when a player gets a new Spaz.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Stats__player_lost_spaz">player_lost_spaz()</a></dt></h4><dd>
|
||||
<p><span>player_lost_spaz(self, player: <a href="#class_ba_Player">ba.Player</a>, killed: bool = False, killer: <a href="#class_ba_Player">ba.Player</a> = None) -> None</span></p>
|
||||
|
||||
<p>Should be called when a player loses a spaz.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Stats__player_scored">player_scored()</a></dt></h4><dd>
|
||||
<p><span>player_scored(self, player: <a href="#class_ba_Player">ba.Player</a>, base_points: int = 1, target: Sequence[float] = None, kill: bool = False, victim_player: <a href="#class_ba_Player">ba.Player</a> = None, scale: float = 1.0, color: Sequence[float] = None, title: Union[str, <a href="#class_ba_Lstr">ba.Lstr</a>] = None, screenmessage: bool = True, display: bool = True, importance: int = 1, showpoints: bool = True, big_message: bool = False) -> int</span></p>
|
||||
@ -4190,6 +4188,12 @@ session.set_activity(foo) and then <a href="#function_ba_newnode">ba.newnode</a>
|
||||
|
||||
<p>Return value is actual score with multipliers and such factored in.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Stats__player_was_killed">player_was_killed()</a></dt></h4><dd>
|
||||
<p><span>player_was_killed(self, player: <a href="#class_ba_Player">ba.Player</a>, killed: bool = False, killer: <a href="#class_ba_Player">ba.Player</a> = None) -> None</span></p>
|
||||
|
||||
<p>Should be called when a player is killed.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Stats__register_player">register_player()</a></dt></h4><dd>
|
||||
<p><span>register_player(self, player: <a href="#class_ba_Player">ba.Player</a>) -> None</span></p>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user