mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-28 18:15:45 +08:00
Modernized assault code a bit
This commit is contained in:
parent
6d0b257934
commit
0742bce678
@ -635,7 +635,7 @@ class GameActivity(Activity[PlayerType, TeamType]):
|
||||
from bastd.actor.playerspaz import PlayerSpazDeathMessage
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
|
||||
player = msg.getspaz(self).player
|
||||
player = msg.playerspaz(self).player
|
||||
killer = msg.killerplayer
|
||||
|
||||
# Inform our score-set of the demise.
|
||||
@ -645,7 +645,8 @@ class GameActivity(Activity[PlayerType, TeamType]):
|
||||
|
||||
# Award the killer points if he's on a different team.
|
||||
if killer and killer.team is not player.team:
|
||||
pts, importance = msg.getspaz(self).get_death_points(msg.how)
|
||||
pts, importance = msg.playerspaz(self).get_death_points(
|
||||
msg.how)
|
||||
if not self.has_ended():
|
||||
self.stats.player_scored(killer,
|
||||
pts,
|
||||
|
||||
@ -60,7 +60,7 @@ class PlayerSpazDeathMessage:
|
||||
self.killerplayer = killerplayer
|
||||
self.how = how
|
||||
|
||||
def getspaz(
|
||||
def playerspaz(
|
||||
self, activity: ba.Activity[PlayerType,
|
||||
TeamType]) -> PlayerSpaz[PlayerType]:
|
||||
"""Return the spaz that died.
|
||||
@ -149,7 +149,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]):
|
||||
|
||||
Note that this may return None if the player has left.
|
||||
"""
|
||||
# Convert invalid references to None.
|
||||
# Return None in the case of a no-longer-valid reference.
|
||||
return self._player if self._player else None
|
||||
|
||||
def connect_controls_to_player(self,
|
||||
@ -295,9 +295,9 @@ class PlayerSpaz(Spaz, Generic[PlayerType]):
|
||||
else:
|
||||
killerplayer = None
|
||||
|
||||
# Convert dead-refs to None.
|
||||
if not killerplayer:
|
||||
killerplayer = None
|
||||
# We should never wind up with a dead-reference here;
|
||||
# we want to use None in that case.
|
||||
assert killerplayer is None or killerplayer
|
||||
|
||||
# Only report if both the player and the activity still exist.
|
||||
if killed and activity is not None and self.getplayer():
|
||||
|
||||
@ -26,17 +26,32 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage
|
||||
from bastd.actor.flag import Flag
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type, List, Dict, Tuple, Sequence, Union
|
||||
|
||||
|
||||
@dataclass
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
base_pos: Sequence[float]
|
||||
flag: Flag
|
||||
score: int = 0
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
class AssaultGame(ba.TeamGameActivity[Player, Team]):
|
||||
"""Game where you score by touching the other team's flag."""
|
||||
|
||||
@classmethod
|
||||
@ -59,106 +74,114 @@ class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
def get_settings(
|
||||
cls,
|
||||
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
|
||||
return [('Score to Win', {'min_value': 1, 'default': 3}),
|
||||
('Time Limit', {
|
||||
'choices': [('None', 0), ('1 Minute', 60),
|
||||
('2 Minutes', 120), ('5 Minutes', 300),
|
||||
('10 Minutes', 600), ('20 Minutes', 1200)],
|
||||
'default': 0}),
|
||||
('Respawn Times', {
|
||||
'choices': [('Shorter', 0.25), ('Short', 0.5),
|
||||
('Normal', 1.0), ('Long', 2.0),
|
||||
('Longer', 4.0)],
|
||||
'default': 1.0}),
|
||||
('Epic Mode', {'default': False})] # yapf: disable
|
||||
return [
|
||||
('Score to Win', {
|
||||
'min_value': 1,
|
||||
'default': 3
|
||||
}),
|
||||
('Time Limit', {
|
||||
'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120),
|
||||
('5 Minutes', 300), ('10 Minutes', 600),
|
||||
('20 Minutes', 1200)],
|
||||
'default': 0
|
||||
}),
|
||||
('Respawn Times', {
|
||||
'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0),
|
||||
('Long', 2.0), ('Longer', 4.0)],
|
||||
'default': 1.0
|
||||
}),
|
||||
('Epic Mode', {
|
||||
'default': False
|
||||
}),
|
||||
]
|
||||
|
||||
def __init__(self, settings: Dict[str, Any]):
|
||||
from bastd.actor.scoreboard import Scoreboard
|
||||
super().__init__(settings)
|
||||
self._scoreboard = Scoreboard()
|
||||
if self.settings_raw['Epic Mode']:
|
||||
self.slow_motion = True
|
||||
self._last_score_time = 0.0
|
||||
self._score_sound = ba.getsound('score')
|
||||
self._base_region_materials: Dict[int, ba.Material] = {}
|
||||
self._epic_mode = bool(settings['Epic Mode'])
|
||||
self._score_to_win = int(settings['Score to Win'])
|
||||
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.FORWARD_MARCH)
|
||||
|
||||
def get_instance_description(self) -> Union[str, Sequence]:
|
||||
if self.settings_raw['Score to Win'] == 1:
|
||||
if self._score_to_win == 1:
|
||||
return 'Touch the enemy flag.'
|
||||
return ('Touch the enemy flag ${ARG1} times.',
|
||||
self.settings_raw['Score to Win'])
|
||||
return 'Touch the enemy flag ${ARG1} times.', self._score_to_win
|
||||
|
||||
def get_instance_scoreboard_description(self) -> Union[str, Sequence]:
|
||||
if self.settings_raw['Score to Win'] == 1:
|
||||
if self._score_to_win == 1:
|
||||
return 'touch 1 flag'
|
||||
return 'touch ${ARG1} flags', self.settings_raw['Score to Win']
|
||||
return 'touch ${ARG1} flags', self._score_to_win
|
||||
|
||||
def on_transition_in(self) -> None:
|
||||
self.default_music = (ba.MusicType.EPIC
|
||||
if self.settings_raw['Epic Mode'] else
|
||||
ba.MusicType.FORWARD_MARCH)
|
||||
super().on_transition_in()
|
||||
def create_team(self, sessionteam: ba.SessionTeam) -> Team:
|
||||
base_pos = self.map.get_flag_position(sessionteam.id)
|
||||
ba.newnode('light',
|
||||
attrs={
|
||||
'position': base_pos,
|
||||
'intensity': 0.6,
|
||||
'height_attenuated': False,
|
||||
'volume_intensity_scale': 0.1,
|
||||
'radius': 0.1,
|
||||
'color': sessionteam.color
|
||||
})
|
||||
self.project_flag_stand(base_pos)
|
||||
flag = Flag(touchable=False,
|
||||
position=base_pos,
|
||||
color=sessionteam.color)
|
||||
team = Team(base_pos=base_pos, flag=flag)
|
||||
|
||||
def on_team_join(self, team: ba.Team) -> None:
|
||||
team.gamedata['score'] = 0
|
||||
mat = self._base_region_materials[sessionteam.id] = ba.Material()
|
||||
mat.add_actions(
|
||||
conditions=('they_have_material', ba.sharedobj('player_material')),
|
||||
actions=(
|
||||
('modify_part_collision', 'collide', True),
|
||||
('modify_part_collision', 'physical', False),
|
||||
('call', 'at_connect', ba.Call(self._handle_base_collide,
|
||||
team)),
|
||||
),
|
||||
)
|
||||
|
||||
ba.newnode(
|
||||
'region',
|
||||
owner=flag.node,
|
||||
attrs={
|
||||
'position': (base_pos[0], base_pos[1] + 0.75, base_pos[2]),
|
||||
'scale': (0.5, 0.5, 0.5),
|
||||
'type': 'sphere',
|
||||
'materials': [self._base_region_materials[sessionteam.id]]
|
||||
})
|
||||
|
||||
return team
|
||||
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
# Can't do this in create_team because the team's color/etc. have
|
||||
# not been wired up yet at that point.
|
||||
self._update_scoreboard()
|
||||
|
||||
def on_begin(self) -> None:
|
||||
from bastd.actor.flag import Flag
|
||||
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()
|
||||
for team in self.teams:
|
||||
mat = self._base_region_materials[team.id] = ba.Material()
|
||||
mat.add_actions(conditions=('they_have_material',
|
||||
ba.sharedobj('player_material')),
|
||||
actions=(('modify_part_collision', 'collide',
|
||||
True), ('modify_part_collision',
|
||||
'physical', False),
|
||||
('call', 'at_connect',
|
||||
ba.Call(self._handle_base_collide,
|
||||
team))))
|
||||
|
||||
# Create a score region and flag for each team.
|
||||
for team in self.teams:
|
||||
team.gamedata['base_pos'] = self.map.get_flag_position(team.id)
|
||||
|
||||
ba.newnode('light',
|
||||
attrs={
|
||||
'position': team.gamedata['base_pos'],
|
||||
'intensity': 0.6,
|
||||
'height_attenuated': False,
|
||||
'volume_intensity_scale': 0.1,
|
||||
'radius': 0.1,
|
||||
'color': team.color
|
||||
})
|
||||
|
||||
self.project_flag_stand(team.gamedata['base_pos'])
|
||||
team.gamedata['flag'] = Flag(touchable=False,
|
||||
position=team.gamedata['base_pos'],
|
||||
color=team.color)
|
||||
basepos = team.gamedata['base_pos']
|
||||
ba.newnode('region',
|
||||
owner=team.gamedata['flag'].node,
|
||||
attrs={
|
||||
'position':
|
||||
(basepos[0], basepos[1] + 0.75, basepos[2]),
|
||||
'scale': (0.5, 0.5, 0.5),
|
||||
'type': 'sphere',
|
||||
'materials': [self._base_region_materials[team.id]]
|
||||
})
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
super().handlemessage(msg) # Augment standard.
|
||||
self.respawn_player(msg.getspaz(self).player)
|
||||
self.respawn_player(msg.playerspaz(self).player)
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
|
||||
def _flash_base(self, team: ba.Team, length: float = 2.0) -> None:
|
||||
def _flash_base(self, team: Team, length: float = 2.0) -> None:
|
||||
light = ba.newnode('light',
|
||||
attrs={
|
||||
'position': team.gamedata['base_pos'],
|
||||
'position': team.base_pos,
|
||||
'height_attenuated': False,
|
||||
'radius': 0.3,
|
||||
'color': team.color
|
||||
@ -166,7 +189,7 @@ class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
ba.animate(light, 'intensity', {0: 0, 0.25: 2.0, 0.5: 0}, loop=True)
|
||||
ba.timer(length, light.delete)
|
||||
|
||||
def _handle_base_collide(self, team: ba.Team) -> None:
|
||||
def _handle_base_collide(self, team: Team) -> None:
|
||||
|
||||
# Attempt to pull a living ba.Player from what we hit.
|
||||
cnode = ba.get_collision_info('opposing_node')
|
||||
@ -179,8 +202,10 @@ class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
if not player or not player.actor:
|
||||
return
|
||||
|
||||
assert isinstance(player, Player)
|
||||
|
||||
# If its another team's player, they scored.
|
||||
player_team: ba.Team[ba.Player] = player.team
|
||||
player_team = player.team
|
||||
if player_team is not team:
|
||||
|
||||
# Prevent multiple simultaneous scores.
|
||||
@ -233,19 +258,18 @@ class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
if player.actor:
|
||||
player.actor.handlemessage(ba.CelebrateMessage(2.0))
|
||||
|
||||
player_team.gamedata['score'] += 1
|
||||
player_team.score += 1
|
||||
self._update_scoreboard()
|
||||
if (player_team.gamedata['score'] >=
|
||||
self.settings_raw['Score to Win']):
|
||||
if player_team.score >= self._score_to_win:
|
||||
self.end_game()
|
||||
|
||||
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)
|
||||
|
||||
def _update_scoreboard(self) -> None:
|
||||
for team in self.teams:
|
||||
self._scoreboard.set_team_value(team, team.gamedata['score'],
|
||||
self.settings_raw['Score to Win'])
|
||||
self._scoreboard.set_team_value(team, team.score,
|
||||
self._score_to_win)
|
||||
|
||||
@ -268,6 +268,8 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
return team
|
||||
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
# Can't do this in create_team because the team's color/etc. have
|
||||
# not been wired up yet at that point.
|
||||
self._spawn_flag_for_team(team)
|
||||
self._update_scoreboard()
|
||||
|
||||
@ -554,7 +556,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
self.respawn_player(msg.getspaz(self).player)
|
||||
self.respawn_player(msg.playerspaz(self).player)
|
||||
elif isinstance(msg, stdflag.FlagDeathMessage):
|
||||
assert isinstance(msg.flag, CTFFlag)
|
||||
ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team))
|
||||
|
||||
@ -327,7 +327,7 @@ class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
player = msg.getspaz(self).player
|
||||
player = msg.playerspaz(self).player
|
||||
if player is self._get_chosen_one_player():
|
||||
killerplayer = msg.killerplayer
|
||||
self._set_chosen_one_player(None if (
|
||||
|
||||
@ -254,7 +254,7 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
super().handlemessage(msg)
|
||||
|
||||
# Respawn only if this team has a flag.
|
||||
player = msg.getspaz(self).player
|
||||
player = msg.playerspaz(self).player
|
||||
if player.team.gamedata['flags_held'] > 0:
|
||||
self.respawn_player(player)
|
||||
else:
|
||||
|
||||
@ -145,7 +145,7 @@ class DeathMatchGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
|
||||
player = msg.getspaz(self).player
|
||||
player = msg.playerspaz(self).player
|
||||
self.respawn_player(player)
|
||||
|
||||
killer = msg.killerplayer
|
||||
|
||||
@ -212,7 +212,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
player = msg.getspaz(self).getplayer()
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
if not player:
|
||||
return
|
||||
self.stats.player_was_killed(player)
|
||||
|
||||
@ -491,7 +491,7 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
player = msg.getspaz(self).player
|
||||
player = msg.playerspaz(self).player
|
||||
|
||||
player.gamedata['lives'] -= 1
|
||||
if player.gamedata['lives'] < 0:
|
||||
|
||||
@ -274,7 +274,7 @@ class FootballTeamGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
elif isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
self.respawn_player(msg.getspaz(self).player)
|
||||
self.respawn_player(msg.playerspaz(self).player)
|
||||
|
||||
# Respawn dead flags.
|
||||
elif isinstance(msg, stdflag.FlagDeathMessage):
|
||||
@ -812,7 +812,7 @@ class FootballCoopGame(ba.CoopGameActivity[ba.Player, ba.Team]):
|
||||
from bastd.actor import respawnicon
|
||||
|
||||
# Respawn dead players.
|
||||
player = msg.getspaz(self).player
|
||||
player = msg.playerspaz(self).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
|
||||
|
||||
@ -341,7 +341,7 @@ class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
# Augment standard behavior...
|
||||
super().handlemessage(msg)
|
||||
self.respawn_player(msg.getspaz(self).player)
|
||||
self.respawn_player(msg.playerspaz(self).player)
|
||||
|
||||
# Respawn dead pucks.
|
||||
elif isinstance(msg, PuckDeathMessage):
|
||||
|
||||
@ -271,7 +271,7 @@ class KeepAwayGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
self.respawn_player(msg.getspaz(self).player)
|
||||
self.respawn_player(msg.playerspaz(self).player)
|
||||
elif isinstance(msg, stdflag.FlagDeathMessage):
|
||||
self._spawn_flag()
|
||||
elif isinstance(
|
||||
|
||||
@ -281,7 +281,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
super().handlemessage(msg) # Augment default.
|
||||
|
||||
# No longer can count as at_flag once dead.
|
||||
player = msg.getspaz(self).player
|
||||
player = msg.playerspaz(self).player
|
||||
player.gamedata['at_flag'] = 0
|
||||
self._update_flag_state()
|
||||
self.respawn_player(player)
|
||||
|
||||
@ -173,7 +173,7 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
# Record the player's moment of death.
|
||||
# assert isinstance(msg.spaz.player
|
||||
msg.getspaz(self).player.death_time = curtime
|
||||
msg.playerspaz(self).player.death_time = curtime
|
||||
|
||||
# In co-op mode, end the game the instant everyone dies
|
||||
# (more accurate looking).
|
||||
|
||||
@ -148,7 +148,8 @@ class NinjaFightGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
# A player has died.
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
super().handlemessage(msg) # do standard stuff
|
||||
self.respawn_player(msg.getspaz(self).player) # kick off a respawn
|
||||
self.respawn_player(
|
||||
msg.playerspaz(self).player) # kick off a respawn
|
||||
|
||||
# A spaz-bot has died.
|
||||
elif isinstance(msg, spazbot.SpazBotDeathMessage):
|
||||
|
||||
@ -1163,7 +1163,7 @@ class OnslaughtGame(ba.CoopGameActivity[ba.Player, ba.Team]):
|
||||
|
||||
elif isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
player = msg.getspaz(self).getplayer()
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
assert player is not None
|
||||
self._a_player_has_been_hurt = True
|
||||
|
||||
|
||||
@ -733,7 +733,7 @@ class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
# Augment default behavior.
|
||||
super().handlemessage(msg)
|
||||
player = msg.getspaz(self).getplayer()
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
if not player:
|
||||
ba.print_error('got no player in PlayerSpazDeathMessage')
|
||||
return
|
||||
|
||||
@ -1127,7 +1127,7 @@ class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]):
|
||||
elif isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
from bastd.actor import respawnicon
|
||||
self._a_player_has_been_killed = True
|
||||
player = msg.getspaz(self).getplayer()
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
if player is None:
|
||||
ba.print_error('FIXME: getplayer() should no'
|
||||
' longer ever be returning None')
|
||||
|
||||
@ -187,7 +187,7 @@ class TargetPracticeGame(ba.TeamGameActivity[ba.Player, ba.Team]):
|
||||
# When players die, respawn them.
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
super().handlemessage(msg) # Do standard stuff.
|
||||
player = msg.getspaz(self).getplayer()
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
assert player is not None
|
||||
self.respawn_player(player) # Kick off a respawn.
|
||||
elif isinstance(msg, Target.TargetHitMessage):
|
||||
|
||||
@ -257,7 +257,7 @@ class TheLastStandGame(ba.CoopGameActivity[ba.Player, ba.Team]):
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
player = msg.getspaz(self).getplayer()
|
||||
player = msg.playerspaz(self).getplayer()
|
||||
if player is None:
|
||||
ba.print_error('FIXME: getplayer() should no longer '
|
||||
'ever be returning None.')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user