mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-26 00:47:10 +08:00
more game modernizing and bug fixes
This commit is contained in:
parent
06600d9eeb
commit
9d7085cb31
@ -4132,16 +4132,16 @@
|
||||
"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-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/68/37e1f6d2afd5d6a4cbbcebba2f3e",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dc/d4/f954892306c82ca4d9c74d335c15",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4d/b8/4cfc2035ec4cdeba78be2aee8aff",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3f/98/9edf61a1b38432213e93b9342a4e",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/43/f76e498f45bb42f2383986d3c15b",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/d6/a9dd60f83d58eb09b1b4c0771588",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/4f/9ded4658cf6e8d8d7fdf9477ae86",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/6b/56d9fa2709eb43be73c00aacb1b5",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a9/41/2e78f2f5dfa4273ce70fc5a59e0e",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9e/3d/12c0ba5235b6750ec0f37726de6e",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8f/9c/edea76ee92634ef9565988c9ef6e",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/35/86/2aeb9cfac9f7639676e149e1323b"
|
||||
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/15/2016db42f7d9d0cd341b29d4cf85",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/74/7a/5361dbc0c2dae7ab52c5501fc21d",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/04/9f/20f97048d27b7eff224cc280a5c3",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d2/d1/c023095a1fc0f2683e6214142ea2",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4e/50/1b6f2eb8ec843e1cf3a96ab0e458",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d6/0a/b979206cca7a41baa8c81d8f6225",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/37/23/4dcfca7889611fd21ece1c39bec5",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7e/6a/093312688ce930585cf2651860b3",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/81/73/63cb8f8ce715a5156bbd3127cee1",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/2c/de/9d59be806cb4a45fa50414276eb1",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f6/af/3eb4c3046770371ea72717e3442e",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5f/3b/645e268f5f3a74acd23edc46ba2f"
|
||||
}
|
||||
2
.idea/inspectionProfiles/Default.xml
generated
2
.idea/inspectionProfiles/Default.xml
generated
@ -52,7 +52,7 @@
|
||||
<inspection_tool class="PyTypeCheckerInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PyTypeHintsInspection" 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">
|
||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="false">
|
||||
<scope name="PyIgnoreUnresolved" level="WARNING" enabled="false">
|
||||
<option name="ignoredIdentifiers">
|
||||
<list>
|
||||
|
||||
@ -698,7 +698,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
||||
'ba.Activity.on_begin() never got called for ' + str(self) +
|
||||
'; did you forget to call it in your on_begin override?')
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def _setup_player_and_team_types(self) -> None:
|
||||
"""Pull player and team types from our typing.Generic params."""
|
||||
|
||||
|
||||
@ -197,7 +197,6 @@ def animate(node: ba.Node,
|
||||
if _ba.app.test_build and not suppress_format_warning:
|
||||
for item in items:
|
||||
# (PyCharm seems to think item is a float, not a tuple)
|
||||
# noinspection PyUnresolvedReferences
|
||||
_ba.time_format_check(timeformat, item[0])
|
||||
|
||||
curve = _ba.newnode('animcurve',
|
||||
@ -223,7 +222,6 @@ def animate(node: ba.Node,
|
||||
# get disconnected.
|
||||
if not loop:
|
||||
# (PyCharm seems to think item is a float, not a tuple)
|
||||
# noinspection PyUnresolvedReferences
|
||||
_ba.timer(int(mult * items[-1][0]) + 1000,
|
||||
curve.delete,
|
||||
timeformat=TimeFormat.MILLISECONDS)
|
||||
@ -264,7 +262,6 @@ def animate_array(node: ba.Node,
|
||||
if _ba.app.test_build and not suppress_format_warning:
|
||||
for item in items:
|
||||
# (PyCharm seems to think item is a float, not a tuple)
|
||||
# noinspection PyUnresolvedReferences
|
||||
_ba.time_format_check(timeformat, item[0])
|
||||
|
||||
if timeformat is TimeFormat.SECONDS:
|
||||
@ -291,7 +288,6 @@ def animate_array(node: ba.Node,
|
||||
# curve after its done its job.
|
||||
if not loop:
|
||||
# (PyCharm seems to think item is a float, not a tuple)
|
||||
# noinspection PyUnresolvedReferences
|
||||
_ba.timer(int(mult * items[-1][0]) + 1000,
|
||||
curve.delete,
|
||||
timeformat=TimeFormat.MILLISECONDS)
|
||||
@ -303,7 +299,6 @@ def animate_array(node: ba.Node,
|
||||
# once we get disconnected.
|
||||
if not loop:
|
||||
# (PyCharm seems to think item is a float, not a tuple)
|
||||
# noinspection PyUnresolvedReferences
|
||||
_ba.timer(int(mult * items[-1][0]) + 1000,
|
||||
combine.delete,
|
||||
timeformat=TimeFormat.MILLISECONDS)
|
||||
|
||||
@ -114,7 +114,6 @@ class ServerCallThread(threading.Thread):
|
||||
_ba.set_thread_name('BA_ServerCallThread')
|
||||
|
||||
# Seems pycharm doesn't know about urllib.parse.
|
||||
# noinspection PyUnresolvedReferences
|
||||
parse = urllib.parse
|
||||
if self._request_type == 'get':
|
||||
response = urllib.request.urlopen(
|
||||
|
||||
@ -31,7 +31,6 @@ if TYPE_CHECKING:
|
||||
|
||||
@dataclass
|
||||
class PowerupMessage:
|
||||
# noinspection PyUnresolvedReferences
|
||||
"""A message telling an object to accept a powerup.
|
||||
|
||||
Category: Message Classes
|
||||
|
||||
@ -115,8 +115,6 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity):
|
||||
def _get_player_score_set_entry(
|
||||
player: ba.SessionPlayer) -> Optional[ba.PlayerRecord]:
|
||||
for p_rec in valid_players:
|
||||
# PyCharm incorrectly thinks valid_players is a List[str]
|
||||
# noinspection PyUnresolvedReferences
|
||||
if p_rec[1].player is player:
|
||||
return p_rec[1]
|
||||
return None
|
||||
|
||||
@ -53,7 +53,7 @@ class _Entry:
|
||||
self._flash_timer: Optional[ba.Timer] = None
|
||||
self._flash_counter: Optional[int] = None
|
||||
self._flash_colors: Optional[bool] = None
|
||||
self._score: Optional[int] = None
|
||||
self._score: Optional[float] = None
|
||||
|
||||
safe_team_color = ba.safecolor(team.color, target_intensity=1.0)
|
||||
|
||||
@ -258,8 +258,8 @@ class _Entry:
|
||||
self._set_flash_colors(not self._flash_colors)
|
||||
|
||||
def set_value(self,
|
||||
score: int,
|
||||
max_score: int = None,
|
||||
score: float,
|
||||
max_score: float = None,
|
||||
countdown: bool = False,
|
||||
flash: bool = True,
|
||||
show_value: bool = True) -> None:
|
||||
@ -360,8 +360,8 @@ class Scoreboard:
|
||||
|
||||
def set_team_value(self,
|
||||
team: ba.Team,
|
||||
score: int,
|
||||
max_score: int = None,
|
||||
score: float,
|
||||
max_score: float = None,
|
||||
countdown: bool = False,
|
||||
flash: bool = True,
|
||||
show_value: bool = True) -> None:
|
||||
@ -373,7 +373,8 @@ class Scoreboard:
|
||||
if '_scoreboard_entry' in team.gamedata:
|
||||
raise Exception('existing _EntryProxy found')
|
||||
team.gamedata['_scoreboard_entry'] = _EntryProxy(self, team)
|
||||
# now set the entry..
|
||||
|
||||
# Now set the entry.
|
||||
self._entries[team.id].set_value(score=score,
|
||||
max_score=max_score,
|
||||
countdown=countdown,
|
||||
|
||||
@ -31,6 +31,7 @@ from typing import TYPE_CHECKING
|
||||
import ba
|
||||
from bastd.actor.playerspaz import PlayerSpaz
|
||||
from bastd.actor.flag import Flag
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type, List, Dict, Sequence, Union
|
||||
@ -85,7 +86,6 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]):
|
||||
return ba.getmaps('team_flag')
|
||||
|
||||
def __init__(self, settings: Dict[str, Any]):
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
super().__init__(settings)
|
||||
self._scoreboard = Scoreboard()
|
||||
self._last_score_time = 0.0
|
||||
|
||||
@ -62,8 +62,7 @@ class CTFFlag(stdflag.Flag):
|
||||
|
||||
def reset_return_times(self) -> None:
|
||||
"""Clear flag related times in the activity."""
|
||||
self.time_out_respawn_time = int(
|
||||
self.activity.settings_raw['Flag Idle Return Time'])
|
||||
self.time_out_respawn_time = int(self.activity.flag_idle_return_time)
|
||||
self.touch_return_time = float(self.activity.flag_touch_return_time)
|
||||
|
||||
@property
|
||||
@ -167,21 +166,17 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
self._all_bases_material = ba.Material()
|
||||
self._last_home_flag_notice_print_time = 0.0
|
||||
self._score_to_win = int(settings['Score to Win'])
|
||||
self._flag_touch_return_time = float(
|
||||
settings['Flag Touch Return Time'])
|
||||
self._epic_mode = bool(settings['Epic Mode'])
|
||||
self._time_limit = float(settings['Time Limit'])
|
||||
|
||||
self.flag_touch_return_time = float(settings['Flag Touch Return Time'])
|
||||
self.flag_idle_return_time = float(settings['Flag Idle return Time'])
|
||||
|
||||
# Base class overrides
|
||||
self.slow_motion = self._epic_mode
|
||||
self.default_music = (ba.MusicType.EPIC if self._epic_mode else
|
||||
ba.MusicType.FLAG_CATCHER)
|
||||
|
||||
@property
|
||||
def flag_touch_return_time(self) -> float:
|
||||
"""How long a flag must be touched for to return it to base."""
|
||||
return self._flag_touch_return_time
|
||||
|
||||
def get_instance_description(self) -> Union[str, Sequence]:
|
||||
if self._score_to_win == 1:
|
||||
return 'Steal the enemy flag.'
|
||||
@ -440,7 +435,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
def _award_players_touching_own_flag(self, team: Team) -> None:
|
||||
for player in team.players:
|
||||
if player.touching_own_flag > 0:
|
||||
return_score = 10 + 5 * int(self._flag_touch_return_time)
|
||||
return_score = 10 + 5 * int(self.flag_touch_return_time)
|
||||
self.stats.player_scored(player,
|
||||
return_score,
|
||||
screenmessage=False)
|
||||
@ -468,7 +463,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
# If return-time is zero, just kill it immediately.. otherwise keep
|
||||
# track of touches and count down.
|
||||
if float(self._flag_touch_return_time) <= 0.0:
|
||||
if float(self.flag_touch_return_time) <= 0.0:
|
||||
assert team.flag is not None
|
||||
if not team.home_flag_at_base and team.flag.held_count == 0:
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ from bastd.actor.flag import Flag
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Optional, Type, List, Dict, Sequence, Union
|
||||
from bastd.actor.respawnicon import RespawnIcon
|
||||
|
||||
|
||||
class ConquestFlag(Flag):
|
||||
@ -57,10 +58,31 @@ class ConquestFlag(Flag):
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
@property
|
||||
def respawn_timer(self) -> Optional[ba.Timer]:
|
||||
"""Type safe access to standard respawn timer."""
|
||||
return self.gamedata.get('respawn_timer', None)
|
||||
|
||||
@respawn_timer.setter
|
||||
def respawn_timer(self, value: Optional[ba.Timer]) -> None:
|
||||
self.gamedata['respawn_timer'] = value
|
||||
|
||||
@property
|
||||
def respawn_icon(self) -> Optional[RespawnIcon]:
|
||||
"""Type safe access to standard respawn icon."""
|
||||
return self.gamedata.get('respawn_icon', None)
|
||||
|
||||
@respawn_icon.setter
|
||||
def respawn_icon(self, value: Optional[RespawnIcon]) -> None:
|
||||
self.gamedata['respawn_icon'] = value
|
||||
|
||||
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.flags_held = 0
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
class ConquestGame(ba.TeamGameActivity[Player, Team]):
|
||||
@ -96,13 +118,18 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]):
|
||||
def __init__(self, settings: Dict[str, Any]):
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
super().__init__(settings)
|
||||
if self.settings_raw['Epic Mode']:
|
||||
self.slow_motion = True
|
||||
self._scoreboard = Scoreboard()
|
||||
self._score_sound = ba.getsound('score')
|
||||
self._swipsound = ba.getsound('swip')
|
||||
self._extraflagmat = ba.Material()
|
||||
self._flags: List[ConquestFlag] = []
|
||||
self._epic_mode = bool(settings['Epic Mode'])
|
||||
self._time_limit = float(settings['Time Limit'])
|
||||
|
||||
# Base class overrides.
|
||||
self.slow_motion = self._epic_mode
|
||||
self.default_music = (ba.MusicType.EPIC
|
||||
if self._epic_mode else ba.MusicType.GRAND_ROMP)
|
||||
|
||||
# We want flags to tell us they've been hit but not react physically.
|
||||
self._extraflagmat.add_actions(
|
||||
@ -116,27 +143,20 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]):
|
||||
def get_instance_description_short(self) -> Union[str, Sequence]:
|
||||
return 'secure all ${ARG1} flags', len(self.map.flag_points)
|
||||
|
||||
def on_transition_in(self) -> None:
|
||||
self.default_music = (ba.MusicType.EPIC
|
||||
if self.settings_raw['Epic Mode'] else
|
||||
ba.MusicType.GRAND_ROMP)
|
||||
super().on_transition_in()
|
||||
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
if self.has_begun():
|
||||
self._update_scores()
|
||||
team.gamedata['flags_held'] = 0
|
||||
|
||||
def on_player_join(self, player: Player) -> None:
|
||||
player.gamedata['respawn_timer'] = None
|
||||
player.respawn_timer = None
|
||||
|
||||
# Only spawn if this player's team has a flag currently.
|
||||
if player.team.gamedata['flags_held'] > 0:
|
||||
if player.team.flags_held > 0:
|
||||
self.spawn_player(player)
|
||||
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.setup_standard_time_limit(self.settings_raw['Time Limit'])
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
self.setup_standard_powerup_drops()
|
||||
|
||||
# Set up flags with marker lights.
|
||||
@ -177,27 +197,27 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
def _update_scores(self) -> None:
|
||||
for team in self.teams:
|
||||
team.gamedata['flags_held'] = 0
|
||||
team.flags_held = 0
|
||||
for flag in self._flags:
|
||||
if flag.team is not None:
|
||||
flag.team.gamedata['flags_held'] += 1
|
||||
flag.team.flags_held += 1
|
||||
for team in self.teams:
|
||||
|
||||
# If a team finds themselves with no flags, cancel all
|
||||
# outstanding spawn-timers.
|
||||
if team.gamedata['flags_held'] == 0:
|
||||
if team.flags_held == 0:
|
||||
for player in team.players:
|
||||
player.gamedata['respawn_timer'] = None
|
||||
player.gamedata['respawn_icon'] = None
|
||||
if team.gamedata['flags_held'] == len(self._flags):
|
||||
player.respawn_timer = None
|
||||
player.respawn_icon = None
|
||||
if team.flags_held == len(self._flags):
|
||||
self.end_game()
|
||||
self._scoreboard.set_team_value(team, team.gamedata['flags_held'],
|
||||
self._scoreboard.set_team_value(team, team.flags_held,
|
||||
len(self._flags))
|
||||
|
||||
def end_game(self) -> None:
|
||||
results = ba.TeamGameResults()
|
||||
for team in self.teams:
|
||||
results.set_team_score(team, team.gamedata['flags_held'])
|
||||
results.set_team_score(team, team.flags_held)
|
||||
self.end(results=results)
|
||||
|
||||
def _flash_flag(self, flag: ConquestFlag, length: float = 1.0) -> None:
|
||||
@ -239,7 +259,7 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]):
|
||||
if (otherplayer.team is flag.team
|
||||
and otherplayer.actor is not None
|
||||
and not otherplayer.is_alive()
|
||||
and otherplayer.gamedata['respawn_timer'] is None):
|
||||
and otherplayer.respawn_timer is None):
|
||||
self.spawn_player(otherplayer)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
@ -249,10 +269,10 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
# Respawn only if this team has a flag.
|
||||
player = msg.getplayer(Player)
|
||||
if player.team.gamedata['flags_held'] > 0:
|
||||
if player.team.flags_held > 0:
|
||||
self.respawn_player(player)
|
||||
else:
|
||||
player.gamedata['respawn_timer'] = None
|
||||
player.respawn_timer = None
|
||||
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
@ -34,6 +34,7 @@ from bastd.actor.playerspaz import PlayerSpaz
|
||||
from bastd.actor.spazbot import BotSet, BouncyBot, SpazBotDeathMessage
|
||||
from bastd.actor.onscreencountdown import OnScreenCountdown
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
from bastd.actor.respawnicon import RespawnIcon
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type, Dict, List, Tuple, Optional
|
||||
@ -42,10 +43,17 @@ if TYPE_CHECKING:
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.respawn_timer: Optional[ba.Timer] = None
|
||||
self.respawn_icon: Optional[RespawnIcon] = None
|
||||
|
||||
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.score = 0
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
||||
@ -88,15 +96,10 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
||||
self._countdown: Optional[OnScreenCountdown] = None
|
||||
self._bots: Optional[BotSet] = None
|
||||
|
||||
# Called when our game is transitioning in but not ready to start.
|
||||
# ..we can go ahead and set our music and whatnot.
|
||||
|
||||
def on_transition_in(self) -> None:
|
||||
# Base class overrides
|
||||
self.default_music = ba.MusicType.FORWARD_MARCH
|
||||
super().on_transition_in()
|
||||
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
team.gamedata['score'] = 0
|
||||
if self.has_begun():
|
||||
self._update_scoreboard()
|
||||
|
||||
@ -142,7 +145,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
||||
player = (spaz.getplayer()
|
||||
if hasattr(spaz, 'getplayer') else None)
|
||||
if player and egg:
|
||||
player.team.gamedata['score'] += 1
|
||||
player.team.score += 1
|
||||
|
||||
# Displays a +1 (and adds to individual player score in
|
||||
# teams mode).
|
||||
@ -201,7 +204,6 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
# Respawn dead players.
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
from bastd.actor import respawnicon
|
||||
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
@ -213,10 +215,9 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
||||
# Respawn them shortly.
|
||||
assert self.initial_player_info is not None
|
||||
respawn_time = 2.0 + len(self.initial_player_info) * 1.0
|
||||
player.gamedata['respawn_timer'] = ba.Timer(
|
||||
player.respawn_timer = ba.Timer(
|
||||
respawn_time, ba.Call(self.spawn_player_if_exists, player))
|
||||
player.gamedata['respawn_icon'] = respawnicon.RespawnIcon(
|
||||
player, respawn_time)
|
||||
player.respawn_icon = RespawnIcon(player, respawn_time)
|
||||
|
||||
# Whenever our evil bunny dies, respawn him and spew some eggs.
|
||||
elif isinstance(msg, SpazBotDeathMessage):
|
||||
@ -235,12 +236,12 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
def _update_scoreboard(self) -> None:
|
||||
for team in self.teams:
|
||||
self._scoreboard.set_team_value(team, team.gamedata['score'])
|
||||
self._scoreboard.set_team_value(team, team.score)
|
||||
|
||||
def end_game(self) -> None:
|
||||
results = ba.TeamGameResults()
|
||||
for team in self.teams:
|
||||
results.set_team_score(team, team.gamedata['score'])
|
||||
results.set_team_score(team, team.score)
|
||||
self.end(results)
|
||||
|
||||
|
||||
|
||||
@ -161,6 +161,12 @@ class Icon(ba.Actor):
|
||||
if lives == 0:
|
||||
ba.timer(0.6, self.update_for_lives)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, ba.DieMessage):
|
||||
self.node.delete()
|
||||
return None
|
||||
return super().handlemessage(msg)
|
||||
|
||||
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
@ -69,10 +69,17 @@ class FootballFlag(stdflag.Flag):
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.respawn_timer: Optional[ba.Timer] = None
|
||||
self.respawn_icon: Optional[RespawnIcon] = None
|
||||
|
||||
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.score = 0
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
||||
@ -130,11 +137,13 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
||||
self._flag: Optional[FootballFlag] = None
|
||||
self._flag_respawn_timer: Optional[ba.Timer] = None
|
||||
self._flag_respawn_light: Optional[ba.NodeActor] = None
|
||||
self._score_to_win = int(settings['Score to Win'])
|
||||
self._time_limit = float(settings['Time Limit'])
|
||||
|
||||
def get_instance_description(self) -> Union[str, Sequence]:
|
||||
touchdowns = self.settings_raw['Score to Win'] / 7
|
||||
touchdowns = self._score_to_win / 7
|
||||
|
||||
# NOTE: if use just touchdowns = self.settings_raw['Score to Win'] // 7
|
||||
# NOTE: if use just touchdowns = self._score_to_win // 7
|
||||
# and we will need to score, for example, 27 points,
|
||||
# we will be required to score 3 (not 4) goals ..
|
||||
touchdowns = math.ceil(touchdowns)
|
||||
@ -143,7 +152,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
||||
return 'Score a touchdown.'
|
||||
|
||||
def get_instance_description_short(self) -> Union[str, Sequence]:
|
||||
touchdowns = self.settings_raw['Score to Win'] / 7
|
||||
touchdowns = self._score_to_win / 7
|
||||
touchdowns = math.ceil(touchdowns)
|
||||
if touchdowns > 1:
|
||||
return 'score ${ARG1} touchdowns', touchdowns
|
||||
@ -155,7 +164,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
self.setup_standard_time_limit(self.settings_raw['Time Limit'])
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
self.setup_standard_powerup_drops()
|
||||
self._flag_spawn_pos = (self.map.get_flag_position(None))
|
||||
self._spawn_flag()
|
||||
@ -182,7 +191,6 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
||||
ba.playsound(self._chant_sound)
|
||||
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
team.gamedata['score'] = 0
|
||||
self._update_scoreboard()
|
||||
|
||||
def _kill_flag(self) -> None:
|
||||
@ -203,7 +211,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
||||
break
|
||||
for team in self.teams:
|
||||
if team.id == i:
|
||||
team.gamedata['score'] += 7
|
||||
team.score += 7
|
||||
|
||||
# Tell all players to celebrate.
|
||||
for player in team.players:
|
||||
@ -218,8 +226,8 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
||||
self.stats.player_scored(self._flag.last_holding_player,
|
||||
50,
|
||||
big_message=True)
|
||||
# end game if we won
|
||||
if team.gamedata['score'] >= self.settings_raw['Score to Win']:
|
||||
# End the game if we won.
|
||||
if team.score >= self._score_to_win:
|
||||
self.end_game()
|
||||
ba.playsound(self._score_sound)
|
||||
ba.playsound(self._cheer_sound)
|
||||
@ -242,15 +250,14 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
||||
def end_game(self) -> None:
|
||||
results = ba.TeamGameResults()
|
||||
for team in self.teams:
|
||||
results.set_team_score(team, team.gamedata['score'])
|
||||
results.set_team_score(team, team.score)
|
||||
self.end(results=results, announce_delay=0.8)
|
||||
|
||||
def _update_scoreboard(self) -> None:
|
||||
win_score = self.settings_raw['Score to Win']
|
||||
assert self._scoreboard is not None
|
||||
for team in self.teams:
|
||||
self._scoreboard.set_team_value(team, team.gamedata['score'],
|
||||
win_score)
|
||||
self._scoreboard.set_team_value(team, team.score,
|
||||
self._score_to_win)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, stdflag.FlagPickedUpMessage):
|
||||
@ -348,7 +355,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
def __init__(self, settings: Dict[str, Any]):
|
||||
settings['map'] = 'Football Stadium'
|
||||
super().__init__(settings)
|
||||
self._preset = self.settings_raw.get('preset', 'rookie')
|
||||
self._preset = settings.get('preset', 'rookie')
|
||||
|
||||
# Load some media we need.
|
||||
self._cheer_sound = ba.getsound('cheer')
|
||||
@ -506,7 +513,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
color=(0.5, 0.4, 0.4))
|
||||
|
||||
for team in [self.teams[0], self._bot_team]:
|
||||
team.gamedata['score'] = 0
|
||||
team.score = 0
|
||||
|
||||
self.update_scores()
|
||||
|
||||
@ -664,7 +671,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
for team in [self.teams[0], self._bot_team]:
|
||||
assert team is not None
|
||||
if team.id == i:
|
||||
team.gamedata['score'] += 7
|
||||
team.score += 7
|
||||
|
||||
# Tell all players (or bots) to celebrate.
|
||||
if i == 0:
|
||||
@ -677,11 +684,11 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
|
||||
# If the good guys scored, add more enemies.
|
||||
if i == 0:
|
||||
if self.teams[0].gamedata['score'] == 7:
|
||||
if self.teams[0].score == 7:
|
||||
assert self._bot_types_7 is not None
|
||||
for bottype in self._bot_types_7:
|
||||
self._spawn_bot(bottype)
|
||||
elif self.teams[0].gamedata['score'] == 14:
|
||||
elif self.teams[0].score == 14:
|
||||
assert self._bot_types_14 is not None
|
||||
for bottype in self._bot_types_14:
|
||||
self._spawn_bot(bottype)
|
||||
@ -717,7 +724,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
def on_continue(self) -> None:
|
||||
# Subtract one touchdown from the bots and get them moving again.
|
||||
assert self._bot_team is not None
|
||||
self._bot_team.gamedata['score'] -= 7
|
||||
self._bot_team.score -= 7
|
||||
self._bots.start_moving()
|
||||
self.update_scores()
|
||||
|
||||
@ -730,9 +737,8 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
for team in [self.teams[0], self._bot_team]:
|
||||
assert team is not None
|
||||
assert self._scoreboard is not None
|
||||
self._scoreboard.set_team_value(team, team.gamedata['score'],
|
||||
win_score)
|
||||
if team.gamedata['score'] >= win_score:
|
||||
self._scoreboard.set_team_value(team, team.score, win_score)
|
||||
if team.score >= win_score:
|
||||
if not have_scoring_team:
|
||||
self.scoring_team = team
|
||||
if team is self._bot_team:
|
||||
@ -745,19 +751,19 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
if self._preset in ['rookie', 'rookie_easy']:
|
||||
self._award_achievement('Rookie Football Victory',
|
||||
sound=False)
|
||||
if self._bot_team.gamedata['score'] == 0:
|
||||
if self._bot_team.score == 0:
|
||||
self._award_achievement(
|
||||
'Rookie Football Shutout', sound=False)
|
||||
elif self._preset in ['pro', 'pro_easy']:
|
||||
self._award_achievement('Pro Football Victory',
|
||||
sound=False)
|
||||
if self._bot_team.gamedata['score'] == 0:
|
||||
if self._bot_team.score == 0:
|
||||
self._award_achievement('Pro Football Shutout',
|
||||
sound=False)
|
||||
elif self._preset in ['uber', 'uber_easy']:
|
||||
self._award_achievement('Uber Football Victory',
|
||||
sound=False)
|
||||
if self._bot_team.gamedata['score'] == 0:
|
||||
if self._bot_team.score == 0:
|
||||
self._award_achievement(
|
||||
'Uber Football Shutout', sound=False)
|
||||
if (not self._player_has_dropped_bomb
|
||||
@ -808,9 +814,9 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
respawn_time = 2.0 + len(self.initial_player_info) * 1.0
|
||||
|
||||
# Respawn them shortly.
|
||||
player.gamedata['respawn_timer'] = ba.Timer(
|
||||
player.respawn_timer = ba.Timer(
|
||||
respawn_time, ba.Call(self.spawn_player_if_exists, player))
|
||||
player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time)
|
||||
player.respawn_icon = RespawnIcon(player, respawn_time)
|
||||
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
|
||||
@ -71,11 +71,21 @@ class Player(ba.Player['Team']):
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.distance_txt: Optional[ba.Node] = None
|
||||
self.last_region = 0
|
||||
self.lap = 0
|
||||
self.distance = 0.0
|
||||
self.finished = False
|
||||
self.rank: Optional[int] = None
|
||||
|
||||
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.time: Optional[float] = None
|
||||
self.lap = 0
|
||||
self.finished = False
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
@ -137,8 +147,6 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
self._race_started = False
|
||||
super().__init__(settings)
|
||||
self._scoreboard = Scoreboard()
|
||||
if self.settings_raw['Epic Mode']:
|
||||
self.slow_motion = True
|
||||
self._score_sound = ba.getsound('score')
|
||||
self._swipsound = ba.getsound('swip')
|
||||
self._last_team_time: Optional[float] = None
|
||||
@ -157,6 +165,18 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
self._player_order_update_timer: Optional[ba.Timer] = None
|
||||
self._start_lights: Optional[List[ba.Node]] = None
|
||||
self._bomb_spawn_timer: Optional[ba.Timer] = None
|
||||
self._laps = int(settings['Laps'])
|
||||
self._entire_team_must_finish = bool(
|
||||
settings.get('Entire Team Must Finish', False))
|
||||
self._time_limit = float(settings['Time Limit'])
|
||||
self._mine_spawning = int(settings['Mine Spawning'])
|
||||
self._bomb_spawning = int(settings['Bomb Spawning'])
|
||||
self._epic_mode = bool(settings['Epic Mode'])
|
||||
|
||||
# Base class overrides.
|
||||
self.slow_motion = self._epic_mode
|
||||
self.default_music = (ba.MusicType.EPIC_RACE
|
||||
if self._epic_mode else ba.MusicType.RACE)
|
||||
|
||||
def get_instance_description(self) -> Union[str, Sequence]:
|
||||
if (isinstance(self.session, ba.DualTeamSession)
|
||||
@ -175,11 +195,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
return 'run 1 lap'
|
||||
|
||||
def on_transition_in(self) -> None:
|
||||
self.default_music = (ba.MusicType.EPIC_RACE
|
||||
if self.settings_raw['Epic Mode'] else
|
||||
ba.MusicType.RACE)
|
||||
super().on_transition_in()
|
||||
|
||||
pts = self.map.get_def_points('race_point')
|
||||
mat = self.race_region_material = ba.Material()
|
||||
mat.add_actions(conditions=('they_have_material',
|
||||
@ -222,7 +238,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
assert isinstance(player, Player)
|
||||
assert isinstance(region, RaceRegion)
|
||||
|
||||
last_region = player.gamedata['last_region']
|
||||
last_region = player.last_region
|
||||
this_region = region.index
|
||||
|
||||
if last_region != this_region:
|
||||
@ -242,29 +258,25 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
else:
|
||||
# If this player is in first, note that this is the
|
||||
# front-most race-point.
|
||||
if player.gamedata['rank'] == 0:
|
||||
if player.rank == 0:
|
||||
self._front_race_region = this_region
|
||||
|
||||
player.gamedata['last_region'] = this_region
|
||||
player.last_region = this_region
|
||||
if last_region >= len(self._regions) - 2 and this_region == 0:
|
||||
team = player.team
|
||||
player.gamedata['lap'] = min(self.settings_raw['Laps'],
|
||||
player.gamedata['lap'] + 1)
|
||||
player.lap = min(self._laps, player.lap + 1)
|
||||
|
||||
# In teams mode with all-must-finish on, the team lap
|
||||
# value is the min of all team players.
|
||||
# Otherwise its the max.
|
||||
if isinstance(
|
||||
self.session, ba.DualTeamSession
|
||||
) and self.settings_raw.get('Entire Team Must Finish'):
|
||||
team.gamedata['lap'] = min(
|
||||
[p.gamedata['lap'] for p in team.players])
|
||||
if isinstance(self.session, ba.DualTeamSession
|
||||
) and self._entire_team_must_finish:
|
||||
team.lap = min([p.lap for p in team.players])
|
||||
else:
|
||||
team.gamedata['lap'] = max(
|
||||
[p.gamedata['lap'] for p in team.players])
|
||||
team.lap = max([p.lap for p in team.players])
|
||||
|
||||
# A player is finishing.
|
||||
if player.gamedata['lap'] == self.settings_raw['Laps']:
|
||||
if player.lap == self._laps:
|
||||
|
||||
# In teams mode, hand out points based on the order
|
||||
# players come in.
|
||||
@ -278,27 +290,22 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
# Flash where the player is.
|
||||
self._flash_player(player, 1.0)
|
||||
player.gamedata['finished'] = True
|
||||
player.finished = True
|
||||
assert player.actor
|
||||
player.actor.handlemessage(
|
||||
ba.DieMessage(immediate=True))
|
||||
|
||||
# Makes sure noone behind them passes them in rank
|
||||
# while finishing.
|
||||
player.gamedata['distance'] = 9999.0
|
||||
player.distance = 9999.0
|
||||
|
||||
# If the whole team has finished the race.
|
||||
if team.gamedata['lap'] == self.settings_raw['Laps']:
|
||||
if team.lap == self._laps:
|
||||
ba.playsound(self._score_sound)
|
||||
player.team.gamedata['finished'] = True
|
||||
player.team.finished = True
|
||||
assert self._timer is not None
|
||||
cur_time = ba.time(
|
||||
timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
start_time = self._timer.getstarttime(
|
||||
timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
self._last_team_time = (
|
||||
player.team.gamedata['time']) = (cur_time -
|
||||
start_time)
|
||||
elapsed = ba.time() - self._timer.getstarttime()
|
||||
self._last_team_time = player.team.time = elapsed
|
||||
self._check_end_game()
|
||||
|
||||
# Team has yet to finish.
|
||||
@ -321,12 +328,11 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
})
|
||||
player.actor.node.connectattr(
|
||||
'torso_position', mathnode, 'input2')
|
||||
tstr = ba.Lstr(
|
||||
resource='lapNumberText',
|
||||
subs=[('${CURRENT}',
|
||||
str(player.gamedata['lap'] + 1)),
|
||||
('${TOTAL}',
|
||||
str(self.settings_raw['Laps']))])
|
||||
tstr = ba.Lstr(resource='lapNumberText',
|
||||
subs=[('${CURRENT}',
|
||||
str(player.lap + 1)),
|
||||
('${TOTAL}', str(self._laps))
|
||||
])
|
||||
txtnode = ba.newnode('text',
|
||||
owner=mathnode,
|
||||
attrs={
|
||||
@ -348,19 +354,8 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
print('Exception printing lap:', exc)
|
||||
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
team.gamedata['time'] = None
|
||||
team.gamedata['lap'] = 0
|
||||
team.gamedata['finished'] = False
|
||||
self._update_scoreboard()
|
||||
|
||||
def on_player_join(self, player: Player) -> None:
|
||||
player.gamedata['last_region'] = 0
|
||||
player.gamedata['lap'] = 0
|
||||
player.gamedata['distance'] = 0.0
|
||||
player.gamedata['finished'] = False
|
||||
player.gamedata['rank'] = None
|
||||
super().on_player_join(player)
|
||||
|
||||
def on_player_leave(self, player: Player) -> None:
|
||||
super().on_player_leave(player)
|
||||
|
||||
@ -368,20 +363,20 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
# is on (otherwise in teams mode everyone could just leave except the
|
||||
# leading player to win).
|
||||
if (isinstance(self.session, ba.DualTeamSession)
|
||||
and self.settings_raw.get('Entire Team Must Finish')):
|
||||
and self._entire_team_must_finish):
|
||||
ba.screenmessage(ba.Lstr(
|
||||
translate=('statements',
|
||||
'${TEAM} is disqualified because ${PLAYER} left'),
|
||||
subs=[('${TEAM}', player.team.name),
|
||||
('${PLAYER}', player.get_name(full=True))]),
|
||||
color=(1, 1, 0))
|
||||
player.team.gamedata['finished'] = True
|
||||
player.team.gamedata['time'] = None
|
||||
player.team.gamedata['lap'] = 0
|
||||
player.team.finished = True
|
||||
player.team.time = None
|
||||
player.team.lap = 0
|
||||
ba.playsound(ba.getsound('boo'))
|
||||
for otherplayer in player.team.players:
|
||||
otherplayer.gamedata['lap'] = 0
|
||||
otherplayer.gamedata['finished'] = True
|
||||
otherplayer.lap = 0
|
||||
otherplayer.finished = True
|
||||
try:
|
||||
if otherplayer.actor is not None:
|
||||
otherplayer.actor.handlemessage(ba.DieMessage())
|
||||
@ -393,28 +388,26 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
def _update_scoreboard(self) -> None:
|
||||
for team in self.teams:
|
||||
distances = [
|
||||
player.gamedata['distance'] for player in team.players
|
||||
]
|
||||
distances = [player.distance for player in team.players]
|
||||
if not distances:
|
||||
teams_dist = 0
|
||||
teams_dist = 0.0
|
||||
else:
|
||||
if (isinstance(self.session, ba.DualTeamSession)
|
||||
and self.settings_raw.get('Entire Team Must Finish')):
|
||||
and self._entire_team_must_finish):
|
||||
teams_dist = min(distances)
|
||||
else:
|
||||
teams_dist = max(distances)
|
||||
self._scoreboard.set_team_value(
|
||||
team,
|
||||
teams_dist,
|
||||
self.settings_raw['Laps'],
|
||||
flash=(teams_dist >= float(self.settings_raw['Laps'])),
|
||||
self._laps,
|
||||
flash=(teams_dist >= float(self._laps)),
|
||||
show_value=False)
|
||||
|
||||
def on_begin(self) -> None:
|
||||
from bastd.actor.onscreentimer import OnScreenTimer
|
||||
super().on_begin()
|
||||
self.setup_standard_time_limit(self.settings_raw['Time Limit'])
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
self.setup_standard_powerup_drops()
|
||||
self._team_finish_pts = 100
|
||||
|
||||
@ -434,16 +427,15 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
}))
|
||||
self._timer = OnScreenTimer()
|
||||
|
||||
if self.settings_raw['Mine Spawning'] != 0:
|
||||
if self._mine_spawning != 0:
|
||||
self._race_mines = [
|
||||
RaceMine(point=p, mine=None)
|
||||
for p in self.map.get_def_points('race_mine')
|
||||
]
|
||||
if self._race_mines:
|
||||
self._race_mine_timer = ba.Timer(
|
||||
0.001 * self.settings_raw['Mine Spawning'],
|
||||
self._update_race_mine,
|
||||
repeat=True)
|
||||
self._race_mine_timer = ba.Timer(0.001 * self._mine_spawning,
|
||||
self._update_race_mine,
|
||||
repeat=True)
|
||||
|
||||
self._scoreboard_timer = ba.Timer(0.25,
|
||||
self._update_scoreboard,
|
||||
@ -516,16 +508,15 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
try:
|
||||
assert isinstance(player.actor, PlayerSpaz)
|
||||
player.actor.connect_controls_to_player()
|
||||
except Exception as exc:
|
||||
print('Exception in race player connects:', exc)
|
||||
except Exception:
|
||||
ba.print_exception('Error in race player connects')
|
||||
assert self._timer is not None
|
||||
self._timer.start()
|
||||
|
||||
if self.settings_raw['Bomb Spawning'] != 0:
|
||||
self._bomb_spawn_timer = ba.Timer(
|
||||
0.001 * self.settings_raw['Bomb Spawning'],
|
||||
self._spawn_bomb,
|
||||
repeat=True)
|
||||
if self._bomb_spawning != 0:
|
||||
self._bomb_spawn_timer = ba.Timer(0.001 * self._bomb_spawning,
|
||||
self._spawn_bomb,
|
||||
repeat=True)
|
||||
|
||||
self._race_started = True
|
||||
|
||||
@ -542,7 +533,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
except Exception:
|
||||
pos = None
|
||||
if pos is not None:
|
||||
r_index = player.gamedata['last_region']
|
||||
r_index = player.last_region
|
||||
rg1 = self._regions[r_index]
|
||||
r1pt = ba.Vec3(rg1.pos[:3])
|
||||
rg2 = self._regions[0] if r_index == len(
|
||||
@ -550,20 +541,17 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
r2pt = ba.Vec3(rg2.pos[:3])
|
||||
r2dist = (pos - r2pt).length()
|
||||
amt = 1.0 - (r2dist / (r2pt - r1pt).length())
|
||||
amt = player.gamedata['lap'] + (r_index + amt) * (
|
||||
1.0 / len(self._regions))
|
||||
player.gamedata['distance'] = amt
|
||||
amt = player.lap + (r_index + amt) * (1.0 / len(self._regions))
|
||||
player.distance = amt
|
||||
|
||||
# Sort players by distance and update their ranks.
|
||||
p_list = [(player.gamedata['distance'], player)
|
||||
for player in self.players]
|
||||
p_list = [(player.distance, player) for player in self.players]
|
||||
|
||||
p_list.sort(reverse=True, key=lambda x: x[0])
|
||||
for i, plr in enumerate(p_list):
|
||||
try:
|
||||
plr[1].gamedata['rank'] = i
|
||||
plr[1].rank = i
|
||||
if plr[1].actor:
|
||||
# noinspection PyUnresolvedReferences
|
||||
node = plr[1].distance_txt
|
||||
if node:
|
||||
node.text = str(i + 1) if plr[1].is_alive() else ''
|
||||
@ -626,13 +614,13 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
ba.timer(0.95, ba.Call(self._make_mine, m_index))
|
||||
|
||||
def spawn_player(self, player: Player) -> ba.Actor:
|
||||
if player.team.gamedata['finished']:
|
||||
if player.team.finished:
|
||||
# FIXME: This is not type-safe!
|
||||
# This call is expected to always return an Actor!
|
||||
# Perhaps we need something like can_spawn_player()...
|
||||
# noinspection PyTypeChecker
|
||||
return None # type: ignore
|
||||
pos = self._regions[player.gamedata['last_region']].pos
|
||||
pos = self._regions[player.last_region].pos
|
||||
|
||||
# Don't use the full region so we're less likely to spawn off a cliff.
|
||||
region_scale = 0.8
|
||||
@ -674,17 +662,14 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
def _check_end_game(self) -> None:
|
||||
|
||||
# If there's no teams left racing, finish.
|
||||
teams_still_in = len(
|
||||
[t for t in self.teams if not t.gamedata['finished']])
|
||||
teams_still_in = len([t for t in self.teams if not t.finished])
|
||||
if teams_still_in == 0:
|
||||
self.end_game()
|
||||
return
|
||||
|
||||
# Count the number of teams that have completed the race.
|
||||
teams_completed = len([
|
||||
t for t in self.teams
|
||||
if t.gamedata['finished'] and t.gamedata['time'] is not None
|
||||
])
|
||||
teams_completed = len(
|
||||
[t for t in self.teams if t.finished and t.time is not None])
|
||||
|
||||
if teams_completed > 0:
|
||||
session = self.session
|
||||
@ -709,22 +694,21 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
# Stop updating our time text, and set it to show the exact last
|
||||
# finish time if we have one. (so users don't get upset if their
|
||||
# final time differs from what they see onscreen by a tiny bit)
|
||||
# final time differs from what they see onscreen by a tiny amount)
|
||||
assert self._timer is not None
|
||||
if self._timer.has_started():
|
||||
cur_time = self._timer.getstarttime(
|
||||
timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
self._timer.stop(
|
||||
endtime=None if self._last_team_time is None else (
|
||||
cur_time + self._last_team_time))
|
||||
self._timer.getstarttime() + self._last_team_time))
|
||||
|
||||
results = ba.TeamGameResults()
|
||||
|
||||
for team in self.teams:
|
||||
if team.gamedata['time'] is not None:
|
||||
results.set_team_score(team, team.gamedata['time'])
|
||||
# If game have ended before we
|
||||
# get any result, use 'fail' screen
|
||||
if team.time is not None:
|
||||
# We store time in seconds, but pass a score in milliseconds.
|
||||
results.set_team_score(team, int(team.time * 1000.0))
|
||||
else:
|
||||
results.set_team_score(team, None)
|
||||
|
||||
# We don't announce a winner in ffa mode since its probably been a
|
||||
# while since the first place guy crossed the finish line so it seems
|
||||
@ -738,10 +722,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
# Augment default behavior.
|
||||
super().handlemessage(msg)
|
||||
player = msg.getplayer(Player)
|
||||
if not player:
|
||||
ba.print_error('got no player in PlayerDiedMessage')
|
||||
return
|
||||
if not player.gamedata['finished']:
|
||||
if not player.finished:
|
||||
self.respawn_player(player, respawn_time=1)
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
@ -35,7 +35,6 @@ if TYPE_CHECKING:
|
||||
class HockeyStadium(ba.Map):
|
||||
"""Stadium map used for ice hockey games."""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import hockey_stadium as defs
|
||||
name = 'Hockey Stadium'
|
||||
|
||||
@ -183,7 +182,6 @@ class FootballStadium(ba.Map):
|
||||
|
||||
class Bridgit(ba.Map):
|
||||
"""Map with a narrow bridge in the middle."""
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import bridgit as defs
|
||||
|
||||
name = 'Bridgit'
|
||||
@ -278,7 +276,6 @@ class Bridgit(ba.Map):
|
||||
class BigG(ba.Map):
|
||||
"""Large G shaped map for racing"""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import big_g as defs
|
||||
|
||||
name = 'Big G'
|
||||
@ -375,7 +372,6 @@ class BigG(ba.Map):
|
||||
class Roundabout(ba.Map):
|
||||
"""CTF map featuring two platforms and a long way around between them"""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import roundabout as defs
|
||||
|
||||
name = 'Roundabout'
|
||||
@ -469,7 +465,6 @@ class Roundabout(ba.Map):
|
||||
class MonkeyFace(ba.Map):
|
||||
"""Map sorta shaped like a monkey face; teehee!"""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import monkey_face as defs
|
||||
|
||||
name = 'Monkey Face'
|
||||
@ -563,7 +558,6 @@ class MonkeyFace(ba.Map):
|
||||
class ZigZag(ba.Map):
|
||||
"""A very long zig-zaggy map"""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import zig_zag as defs
|
||||
|
||||
name = 'Zigzag'
|
||||
@ -657,7 +651,6 @@ class ZigZag(ba.Map):
|
||||
class ThePad(ba.Map):
|
||||
"""A simple square shaped map with a raised edge."""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import the_pad as defs
|
||||
|
||||
name = 'The Pad'
|
||||
@ -738,7 +731,6 @@ class ThePad(ba.Map):
|
||||
class DoomShroom(ba.Map):
|
||||
"""A giant mushroom. Of doom."""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import doom_shroom as defs
|
||||
|
||||
name = 'Doom Shroom'
|
||||
@ -831,7 +823,6 @@ class DoomShroom(ba.Map):
|
||||
class LakeFrigid(ba.Map):
|
||||
"""An icy lake fit for racing."""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import lake_frigid as defs
|
||||
|
||||
name = 'Lake Frigid'
|
||||
@ -912,7 +903,6 @@ class LakeFrigid(ba.Map):
|
||||
class TipTop(ba.Map):
|
||||
"""A pointy map good for king-of-the-hill-ish games."""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import tip_top as defs
|
||||
|
||||
name = 'Tip Top'
|
||||
@ -984,7 +974,6 @@ class TipTop(ba.Map):
|
||||
class CragCastle(ba.Map):
|
||||
"""A lovely castle map."""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import crag_castle as defs
|
||||
|
||||
name = 'Crag Castle'
|
||||
@ -1185,7 +1174,6 @@ class TowerD(ba.Map):
|
||||
class HappyThoughts(ba.Map):
|
||||
"""Flying map."""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import happy_thoughts as defs
|
||||
|
||||
name = 'Happy Thoughts'
|
||||
@ -1291,7 +1279,6 @@ class HappyThoughts(ba.Map):
|
||||
class StepRightUp(ba.Map):
|
||||
"""Wide stepped map good for CTF or Assault."""
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from bastd.mapdata import step_right_up as defs
|
||||
|
||||
name = 'Step Right Up'
|
||||
|
||||
@ -268,7 +268,6 @@ class ColorPickerExact(popup.PopupWindow):
|
||||
# color to the delegate, so start doing that...
|
||||
self._update_for_color()
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def _update_for_color(self) -> None:
|
||||
if not self.root_widget:
|
||||
return
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||
<h4><em>last updated on 2020-05-20 for Ballistica version 1.5.0 build 20025</em></h4>
|
||||
<h4><em>last updated on 2020-05-21 for Ballistica version 1.5.0 build 20025</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>
|
||||
|
||||
@ -37,7 +37,6 @@ from typing import TYPE_CHECKING
|
||||
|
||||
# Pull in some standard snippets we want to expose.
|
||||
# pylint: disable=unused-import
|
||||
# noinspection PyUnresolvedReferences
|
||||
from efrotools.snippets import (
|
||||
PROJROOT, snippets_main, formatcode, formatscripts, formatmakefile,
|
||||
cpplint, pylint, runpylint, mypy, runmypy, dmypy, tool_config_install,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user