bascenev1lib.game.easteregghunt
Provides an easter egg hunt game.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides an easter egg hunt game.""" 4 5# ba_meta require api 8 6# (see https://ballistica.net/wiki/meta-tag-system) 7 8from __future__ import annotations 9 10import random 11from typing import TYPE_CHECKING 12 13from bascenev1lib.actor.bomb import Bomb 14from bascenev1lib.actor.playerspaz import PlayerSpaz 15from bascenev1lib.actor.spazbot import SpazBotSet, BouncyBot, SpazBotDiedMessage 16from bascenev1lib.actor.onscreencountdown import OnScreenCountdown 17from bascenev1lib.actor.scoreboard import Scoreboard 18from bascenev1lib.actor.respawnicon import RespawnIcon 19from bascenev1lib.gameutils import SharedObjects 20import bascenev1 as bs 21 22if TYPE_CHECKING: 23 from typing import Any 24 25 26class Player(bs.Player['Team']): 27 """Our player type for this game.""" 28 29 def __init__(self) -> None: 30 self.respawn_timer: bs.Timer | None = None 31 self.respawn_icon: RespawnIcon | None = None 32 33 34class Team(bs.Team[Player]): 35 """Our team type for this game.""" 36 37 def __init__(self) -> None: 38 self.score = 0 39 40 41# ba_meta export bascenev1.GameActivity 42class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]): 43 """A game where score is based on collecting eggs.""" 44 45 name = 'Easter Egg Hunt' 46 description = 'Gather eggs!' 47 available_settings = [ 48 bs.BoolSetting('Pro Mode', default=False), 49 bs.BoolSetting('Epic Mode', default=False), 50 ] 51 scoreconfig = bs.ScoreConfig(label='Score', scoretype=bs.ScoreType.POINTS) 52 53 # We're currently hard-coded for one map. 54 @classmethod 55 def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: 56 return ['Tower D'] 57 58 # We support teams, free-for-all, and co-op sessions. 59 @classmethod 60 def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: 61 return ( 62 issubclass(sessiontype, bs.CoopSession) 63 or issubclass(sessiontype, bs.DualTeamSession) 64 or issubclass(sessiontype, bs.FreeForAllSession) 65 ) 66 67 def __init__(self, settings: dict): 68 super().__init__(settings) 69 shared = SharedObjects.get() 70 self._last_player_death_time = None 71 self._scoreboard = Scoreboard() 72 self.egg_mesh = bs.getmesh('egg') 73 self.egg_tex_1 = bs.gettexture('eggTex1') 74 self.egg_tex_2 = bs.gettexture('eggTex2') 75 self.egg_tex_3 = bs.gettexture('eggTex3') 76 self._collect_sound = bs.getsound('powerup01') 77 self._pro_mode = settings.get('Pro Mode', False) 78 self._epic_mode = settings.get('Epic Mode', False) 79 self._max_eggs = 1.0 80 self.egg_material = bs.Material() 81 self.egg_material.add_actions( 82 conditions=('they_have_material', shared.player_material), 83 actions=(('call', 'at_connect', self._on_egg_player_collide),), 84 ) 85 self._eggs: list[Egg] = [] 86 self._update_timer: bs.Timer | None = None 87 self._countdown: OnScreenCountdown | None = None 88 self._bots: SpazBotSet | None = None 89 90 # Base class overrides 91 self.slow_motion = self._epic_mode 92 self.default_music = ( 93 bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH 94 ) 95 96 def on_team_join(self, team: Team) -> None: 97 if self.has_begun(): 98 self._update_scoreboard() 99 100 # Called when our game actually starts. 101 def on_begin(self) -> None: 102 from bascenev1lib.maps import TowerD 103 104 # There's a player-wall on the tower-d level to prevent 105 # players from getting up on the stairs.. we wanna kill that. 106 gamemap = self.map 107 assert isinstance(gamemap, TowerD) 108 gamemap.player_wall.delete() 109 super().on_begin() 110 self._update_scoreboard() 111 self._update_timer = bs.Timer(0.25, self._update, repeat=True) 112 self._countdown = OnScreenCountdown(60, endcall=self.end_game) 113 bs.timer(4.0, self._countdown.start) 114 self._bots = SpazBotSet() 115 116 # Spawn evil bunny in co-op only. 117 if isinstance(self.session, bs.CoopSession) and self._pro_mode: 118 self._spawn_evil_bunny() 119 120 # Overriding the default character spawning. 121 def spawn_player(self, player: Player) -> bs.Actor: 122 spaz = self.spawn_player_spaz(player) 123 spaz.connect_controls_to_player() 124 return spaz 125 126 def _spawn_evil_bunny(self) -> None: 127 assert self._bots is not None 128 self._bots.spawn_bot(BouncyBot, pos=(6, 4, -7.8), spawn_time=10.0) 129 130 def _on_egg_player_collide(self) -> None: 131 if self.has_ended(): 132 return 133 collision = bs.getcollision() 134 135 # Be defensive here; we could be hitting the corpse of a player 136 # who just left/etc. 137 try: 138 egg = collision.sourcenode.getdelegate(Egg, True) 139 player = collision.opposingnode.getdelegate( 140 PlayerSpaz, True 141 ).getplayer(Player, True) 142 except bs.NotFoundError: 143 return 144 145 player.team.score += 1 146 147 # Displays a +1 (and adds to individual player score in 148 # teams mode). 149 self.stats.player_scored(player, 1, screenmessage=False) 150 if self._max_eggs < 5: 151 self._max_eggs += 1.0 152 elif self._max_eggs < 10: 153 self._max_eggs += 0.5 154 elif self._max_eggs < 30: 155 self._max_eggs += 0.3 156 self._update_scoreboard() 157 self._collect_sound.play(0.5, position=egg.node.position) 158 159 # Create a flash. 160 light = bs.newnode( 161 'light', 162 attrs={ 163 'position': egg.node.position, 164 'height_attenuated': False, 165 'radius': 0.1, 166 'color': (1, 1, 0), 167 }, 168 ) 169 bs.animate(light, 'intensity', {0: 0, 0.1: 1.0, 0.2: 0}, loop=False) 170 bs.timer(0.200, light.delete) 171 egg.handlemessage(bs.DieMessage()) 172 173 def _update(self) -> None: 174 # Misc. periodic updating. 175 xpos = random.uniform(-7.1, 6.0) 176 ypos = random.uniform(3.5, 3.5) 177 zpos = random.uniform(-8.2, 3.7) 178 179 # Prune dead eggs from our list. 180 self._eggs = [e for e in self._eggs if e] 181 182 # Spawn more eggs if we've got space. 183 if len(self._eggs) < int(self._max_eggs): 184 # Occasionally spawn a land-mine in addition. 185 if self._pro_mode and random.random() < 0.25: 186 mine = Bomb( 187 position=(xpos, ypos, zpos), bomb_type='land_mine' 188 ).autoretain() 189 mine.arm() 190 else: 191 self._eggs.append(Egg(position=(xpos, ypos, zpos))) 192 193 # Various high-level game events come through this method. 194 def handlemessage(self, msg: Any) -> Any: 195 # Respawn dead players. 196 if isinstance(msg, bs.PlayerDiedMessage): 197 # Augment standard behavior. 198 super().handlemessage(msg) 199 200 # Respawn them shortly. 201 player = msg.getplayer(Player) 202 assert self.initialplayerinfos is not None 203 respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0 204 player.respawn_timer = bs.Timer( 205 respawn_time, bs.Call(self.spawn_player_if_exists, player) 206 ) 207 player.respawn_icon = RespawnIcon(player, respawn_time) 208 209 # Whenever our evil bunny dies, respawn him and spew some eggs. 210 elif isinstance(msg, SpazBotDiedMessage): 211 self._spawn_evil_bunny() 212 assert msg.spazbot.node 213 pos = msg.spazbot.node.position 214 for _i in range(6): 215 spread = 0.4 216 self._eggs.append( 217 Egg( 218 position=( 219 pos[0] + random.uniform(-spread, spread), 220 pos[1] + random.uniform(-spread, spread), 221 pos[2] + random.uniform(-spread, spread), 222 ) 223 ) 224 ) 225 else: 226 # Default handler. 227 return super().handlemessage(msg) 228 return None 229 230 def _update_scoreboard(self) -> None: 231 for team in self.teams: 232 self._scoreboard.set_team_value(team, team.score) 233 234 def end_game(self) -> None: 235 results = bs.GameResults() 236 for team in self.teams: 237 results.set_team_score(team, team.score) 238 self.end(results) 239 240 241class Egg(bs.Actor): 242 """A lovely egg that can be picked up for points.""" 243 244 def __init__(self, position: tuple[float, float, float] = (0.0, 1.0, 0.0)): 245 super().__init__() 246 activity = self.activity 247 assert isinstance(activity, EasterEggHuntGame) 248 shared = SharedObjects.get() 249 250 # Spawn just above the provided point. 251 self._spawn_pos = (position[0], position[1] + 1.0, position[2]) 252 ctex = (activity.egg_tex_1, activity.egg_tex_2, activity.egg_tex_3)[ 253 random.randrange(3) 254 ] 255 mats = [shared.object_material, activity.egg_material] 256 self.node = bs.newnode( 257 'prop', 258 delegate=self, 259 attrs={ 260 'mesh': activity.egg_mesh, 261 'color_texture': ctex, 262 'body': 'capsule', 263 'reflection': 'soft', 264 'mesh_scale': 0.5, 265 'body_scale': 0.6, 266 'density': 4.0, 267 'reflection_scale': [0.15], 268 'shadow_size': 0.6, 269 'position': self._spawn_pos, 270 'materials': mats, 271 }, 272 ) 273 274 def exists(self) -> bool: 275 return bool(self.node) 276 277 def handlemessage(self, msg: Any) -> Any: 278 if isinstance(msg, bs.DieMessage): 279 if self.node: 280 self.node.delete() 281 elif isinstance(msg, bs.HitMessage): 282 if self.node: 283 assert msg.force_direction is not None 284 self.node.handlemessage( 285 'impulse', 286 msg.pos[0], 287 msg.pos[1], 288 msg.pos[2], 289 msg.velocity[0], 290 msg.velocity[1], 291 msg.velocity[2], 292 1.0 * msg.magnitude, 293 1.0 * msg.velocity_magnitude, 294 msg.radius, 295 0, 296 msg.force_direction[0], 297 msg.force_direction[1], 298 msg.force_direction[2], 299 ) 300 else: 301 super().handlemessage(msg)
27class Player(bs.Player['Team']): 28 """Our player type for this game.""" 29 30 def __init__(self) -> None: 31 self.respawn_timer: bs.Timer | None = None 32 self.respawn_icon: RespawnIcon | None = None
Our player type for this game.
Inherited Members
- bascenev1._player.Player
- character
- actor
- color
- highlight
- on_expire
- team
- customdata
- sessionplayer
- node
- position
- exists
- getname
- is_alive
- get_icon
- assigninput
- resetinput
35class Team(bs.Team[Player]): 36 """Our team type for this game.""" 37 38 def __init__(self) -> None: 39 self.score = 0
Our team type for this game.
Inherited Members
- bascenev1._team.Team
- players
- id
- name
- color
- manual_init
- customdata
- on_expire
- sessionteam
43class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]): 44 """A game where score is based on collecting eggs.""" 45 46 name = 'Easter Egg Hunt' 47 description = 'Gather eggs!' 48 available_settings = [ 49 bs.BoolSetting('Pro Mode', default=False), 50 bs.BoolSetting('Epic Mode', default=False), 51 ] 52 scoreconfig = bs.ScoreConfig(label='Score', scoretype=bs.ScoreType.POINTS) 53 54 # We're currently hard-coded for one map. 55 @classmethod 56 def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: 57 return ['Tower D'] 58 59 # We support teams, free-for-all, and co-op sessions. 60 @classmethod 61 def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: 62 return ( 63 issubclass(sessiontype, bs.CoopSession) 64 or issubclass(sessiontype, bs.DualTeamSession) 65 or issubclass(sessiontype, bs.FreeForAllSession) 66 ) 67 68 def __init__(self, settings: dict): 69 super().__init__(settings) 70 shared = SharedObjects.get() 71 self._last_player_death_time = None 72 self._scoreboard = Scoreboard() 73 self.egg_mesh = bs.getmesh('egg') 74 self.egg_tex_1 = bs.gettexture('eggTex1') 75 self.egg_tex_2 = bs.gettexture('eggTex2') 76 self.egg_tex_3 = bs.gettexture('eggTex3') 77 self._collect_sound = bs.getsound('powerup01') 78 self._pro_mode = settings.get('Pro Mode', False) 79 self._epic_mode = settings.get('Epic Mode', False) 80 self._max_eggs = 1.0 81 self.egg_material = bs.Material() 82 self.egg_material.add_actions( 83 conditions=('they_have_material', shared.player_material), 84 actions=(('call', 'at_connect', self._on_egg_player_collide),), 85 ) 86 self._eggs: list[Egg] = [] 87 self._update_timer: bs.Timer | None = None 88 self._countdown: OnScreenCountdown | None = None 89 self._bots: SpazBotSet | None = None 90 91 # Base class overrides 92 self.slow_motion = self._epic_mode 93 self.default_music = ( 94 bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH 95 ) 96 97 def on_team_join(self, team: Team) -> None: 98 if self.has_begun(): 99 self._update_scoreboard() 100 101 # Called when our game actually starts. 102 def on_begin(self) -> None: 103 from bascenev1lib.maps import TowerD 104 105 # There's a player-wall on the tower-d level to prevent 106 # players from getting up on the stairs.. we wanna kill that. 107 gamemap = self.map 108 assert isinstance(gamemap, TowerD) 109 gamemap.player_wall.delete() 110 super().on_begin() 111 self._update_scoreboard() 112 self._update_timer = bs.Timer(0.25, self._update, repeat=True) 113 self._countdown = OnScreenCountdown(60, endcall=self.end_game) 114 bs.timer(4.0, self._countdown.start) 115 self._bots = SpazBotSet() 116 117 # Spawn evil bunny in co-op only. 118 if isinstance(self.session, bs.CoopSession) and self._pro_mode: 119 self._spawn_evil_bunny() 120 121 # Overriding the default character spawning. 122 def spawn_player(self, player: Player) -> bs.Actor: 123 spaz = self.spawn_player_spaz(player) 124 spaz.connect_controls_to_player() 125 return spaz 126 127 def _spawn_evil_bunny(self) -> None: 128 assert self._bots is not None 129 self._bots.spawn_bot(BouncyBot, pos=(6, 4, -7.8), spawn_time=10.0) 130 131 def _on_egg_player_collide(self) -> None: 132 if self.has_ended(): 133 return 134 collision = bs.getcollision() 135 136 # Be defensive here; we could be hitting the corpse of a player 137 # who just left/etc. 138 try: 139 egg = collision.sourcenode.getdelegate(Egg, True) 140 player = collision.opposingnode.getdelegate( 141 PlayerSpaz, True 142 ).getplayer(Player, True) 143 except bs.NotFoundError: 144 return 145 146 player.team.score += 1 147 148 # Displays a +1 (and adds to individual player score in 149 # teams mode). 150 self.stats.player_scored(player, 1, screenmessage=False) 151 if self._max_eggs < 5: 152 self._max_eggs += 1.0 153 elif self._max_eggs < 10: 154 self._max_eggs += 0.5 155 elif self._max_eggs < 30: 156 self._max_eggs += 0.3 157 self._update_scoreboard() 158 self._collect_sound.play(0.5, position=egg.node.position) 159 160 # Create a flash. 161 light = bs.newnode( 162 'light', 163 attrs={ 164 'position': egg.node.position, 165 'height_attenuated': False, 166 'radius': 0.1, 167 'color': (1, 1, 0), 168 }, 169 ) 170 bs.animate(light, 'intensity', {0: 0, 0.1: 1.0, 0.2: 0}, loop=False) 171 bs.timer(0.200, light.delete) 172 egg.handlemessage(bs.DieMessage()) 173 174 def _update(self) -> None: 175 # Misc. periodic updating. 176 xpos = random.uniform(-7.1, 6.0) 177 ypos = random.uniform(3.5, 3.5) 178 zpos = random.uniform(-8.2, 3.7) 179 180 # Prune dead eggs from our list. 181 self._eggs = [e for e in self._eggs if e] 182 183 # Spawn more eggs if we've got space. 184 if len(self._eggs) < int(self._max_eggs): 185 # Occasionally spawn a land-mine in addition. 186 if self._pro_mode and random.random() < 0.25: 187 mine = Bomb( 188 position=(xpos, ypos, zpos), bomb_type='land_mine' 189 ).autoretain() 190 mine.arm() 191 else: 192 self._eggs.append(Egg(position=(xpos, ypos, zpos))) 193 194 # Various high-level game events come through this method. 195 def handlemessage(self, msg: Any) -> Any: 196 # Respawn dead players. 197 if isinstance(msg, bs.PlayerDiedMessage): 198 # Augment standard behavior. 199 super().handlemessage(msg) 200 201 # Respawn them shortly. 202 player = msg.getplayer(Player) 203 assert self.initialplayerinfos is not None 204 respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0 205 player.respawn_timer = bs.Timer( 206 respawn_time, bs.Call(self.spawn_player_if_exists, player) 207 ) 208 player.respawn_icon = RespawnIcon(player, respawn_time) 209 210 # Whenever our evil bunny dies, respawn him and spew some eggs. 211 elif isinstance(msg, SpazBotDiedMessage): 212 self._spawn_evil_bunny() 213 assert msg.spazbot.node 214 pos = msg.spazbot.node.position 215 for _i in range(6): 216 spread = 0.4 217 self._eggs.append( 218 Egg( 219 position=( 220 pos[0] + random.uniform(-spread, spread), 221 pos[1] + random.uniform(-spread, spread), 222 pos[2] + random.uniform(-spread, spread), 223 ) 224 ) 225 ) 226 else: 227 # Default handler. 228 return super().handlemessage(msg) 229 return None 230 231 def _update_scoreboard(self) -> None: 232 for team in self.teams: 233 self._scoreboard.set_team_value(team, team.score) 234 235 def end_game(self) -> None: 236 results = bs.GameResults() 237 for team in self.teams: 238 results.set_team_score(team, team.score) 239 self.end(results)
A game where score is based on collecting eggs.
68 def __init__(self, settings: dict): 69 super().__init__(settings) 70 shared = SharedObjects.get() 71 self._last_player_death_time = None 72 self._scoreboard = Scoreboard() 73 self.egg_mesh = bs.getmesh('egg') 74 self.egg_tex_1 = bs.gettexture('eggTex1') 75 self.egg_tex_2 = bs.gettexture('eggTex2') 76 self.egg_tex_3 = bs.gettexture('eggTex3') 77 self._collect_sound = bs.getsound('powerup01') 78 self._pro_mode = settings.get('Pro Mode', False) 79 self._epic_mode = settings.get('Epic Mode', False) 80 self._max_eggs = 1.0 81 self.egg_material = bs.Material() 82 self.egg_material.add_actions( 83 conditions=('they_have_material', shared.player_material), 84 actions=(('call', 'at_connect', self._on_egg_player_collide),), 85 ) 86 self._eggs: list[Egg] = [] 87 self._update_timer: bs.Timer | None = None 88 self._countdown: OnScreenCountdown | None = None 89 self._bots: SpazBotSet | None = None 90 91 # Base class overrides 92 self.slow_motion = self._epic_mode 93 self.default_music = ( 94 bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH 95 )
Instantiate the Activity.
55 @classmethod 56 def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: 57 return ['Tower D']
Called by the default bascenev1.GameActivity.create_settings_ui() implementation; should return a list of map names valid for this game-type for the given bascenev1.Session type.
60 @classmethod 61 def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: 62 return ( 63 issubclass(sessiontype, bs.CoopSession) 64 or issubclass(sessiontype, bs.DualTeamSession) 65 or issubclass(sessiontype, bs.FreeForAllSession) 66 )
Class method override; returns True for ba.DualTeamSessions and ba.FreeForAllSessions; False otherwise.
Called when a new bascenev1.Team joins the Activity.
(including the initial set of Teams)
102 def on_begin(self) -> None: 103 from bascenev1lib.maps import TowerD 104 105 # There's a player-wall on the tower-d level to prevent 106 # players from getting up on the stairs.. we wanna kill that. 107 gamemap = self.map 108 assert isinstance(gamemap, TowerD) 109 gamemap.player_wall.delete() 110 super().on_begin() 111 self._update_scoreboard() 112 self._update_timer = bs.Timer(0.25, self._update, repeat=True) 113 self._countdown = OnScreenCountdown(60, endcall=self.end_game) 114 bs.timer(4.0, self._countdown.start) 115 self._bots = SpazBotSet() 116 117 # Spawn evil bunny in co-op only. 118 if isinstance(self.session, bs.CoopSession) and self._pro_mode: 119 self._spawn_evil_bunny()
Called once the previous Activity has finished transitioning out.
At this point the activity's initial players and teams are filled in and it should begin its actual game logic.
122 def spawn_player(self, player: Player) -> bs.Actor: 123 spaz = self.spawn_player_spaz(player) 124 spaz.connect_controls_to_player() 125 return spaz
Spawn something for the provided bascenev1.Player.
The default implementation simply calls spawn_player_spaz().
195 def handlemessage(self, msg: Any) -> Any: 196 # Respawn dead players. 197 if isinstance(msg, bs.PlayerDiedMessage): 198 # Augment standard behavior. 199 super().handlemessage(msg) 200 201 # Respawn them shortly. 202 player = msg.getplayer(Player) 203 assert self.initialplayerinfos is not None 204 respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0 205 player.respawn_timer = bs.Timer( 206 respawn_time, bs.Call(self.spawn_player_if_exists, player) 207 ) 208 player.respawn_icon = RespawnIcon(player, respawn_time) 209 210 # Whenever our evil bunny dies, respawn him and spew some eggs. 211 elif isinstance(msg, SpazBotDiedMessage): 212 self._spawn_evil_bunny() 213 assert msg.spazbot.node 214 pos = msg.spazbot.node.position 215 for _i in range(6): 216 spread = 0.4 217 self._eggs.append( 218 Egg( 219 position=( 220 pos[0] + random.uniform(-spread, spread), 221 pos[1] + random.uniform(-spread, spread), 222 pos[2] + random.uniform(-spread, spread), 223 ) 224 ) 225 ) 226 else: 227 # Default handler. 228 return super().handlemessage(msg) 229 return None
General message handling; can be passed any message object.
235 def end_game(self) -> None: 236 results = bs.GameResults() 237 for team in self.teams: 238 results.set_team_score(team, team.score) 239 self.end(results)
Tell the game to wrap up and call bascenev1.Activity.end().
This method should be overridden by subclasses. A game should always be prepared to end and deliver results, even if there is no 'winner' yet; this way things like the standard time-limit (bascenev1.GameActivity.setup_standard_time_limit()) will work with the game.
Inherited Members
- bascenev1._teamgame.TeamGameActivity
- on_transition_in
- spawn_player_spaz
- end
- bascenev1._gameactivity.GameActivity
- tips
- allow_pausing
- allow_kick_idle_players
- show_kill_points
- create_settings_ui
- getscoreconfig
- getname
- get_display_string
- get_team_display_string
- get_description
- get_description_display_string
- get_available_settings
- get_settings_display_string
- initialplayerinfos
- map
- get_instance_display_string
- get_instance_scoreboard_display_string
- get_instance_description
- get_instance_description_short
- on_continue
- is_waiting_for_continue
- continue_or_end_game
- on_player_join
- respawn_player
- spawn_player_if_exists
- setup_standard_powerup_drops
- setup_standard_time_limit
- show_zoom_message
- bascenev1._activity.Activity
- settings_raw
- teams
- players
- announce_player_deaths
- is_joining_activity
- use_fixed_vr_overlay
- inherits_slow_motion
- inherits_music
- inherits_vr_camera_offset
- inherits_vr_overlay_center
- inherits_tint
- allow_mid_activity_joins
- transition_time
- can_show_ad_on_death
- paused_text
- preloads
- lobby
- context
- globalsnode
- stats
- on_expire
- customdata
- expired
- playertype
- teamtype
- retain_actor
- add_actor_weak_ref
- session
- on_player_leave
- on_team_leave
- on_transition_out
- has_transitioned_in
- has_begun
- has_ended
- is_transitioning_out
- transition_out
- create_player
- create_team
- bascenev1._dependency.DependencyComponent
- dep_is_present
- get_dynamic_deps
242class Egg(bs.Actor): 243 """A lovely egg that can be picked up for points.""" 244 245 def __init__(self, position: tuple[float, float, float] = (0.0, 1.0, 0.0)): 246 super().__init__() 247 activity = self.activity 248 assert isinstance(activity, EasterEggHuntGame) 249 shared = SharedObjects.get() 250 251 # Spawn just above the provided point. 252 self._spawn_pos = (position[0], position[1] + 1.0, position[2]) 253 ctex = (activity.egg_tex_1, activity.egg_tex_2, activity.egg_tex_3)[ 254 random.randrange(3) 255 ] 256 mats = [shared.object_material, activity.egg_material] 257 self.node = bs.newnode( 258 'prop', 259 delegate=self, 260 attrs={ 261 'mesh': activity.egg_mesh, 262 'color_texture': ctex, 263 'body': 'capsule', 264 'reflection': 'soft', 265 'mesh_scale': 0.5, 266 'body_scale': 0.6, 267 'density': 4.0, 268 'reflection_scale': [0.15], 269 'shadow_size': 0.6, 270 'position': self._spawn_pos, 271 'materials': mats, 272 }, 273 ) 274 275 def exists(self) -> bool: 276 return bool(self.node) 277 278 def handlemessage(self, msg: Any) -> Any: 279 if isinstance(msg, bs.DieMessage): 280 if self.node: 281 self.node.delete() 282 elif isinstance(msg, bs.HitMessage): 283 if self.node: 284 assert msg.force_direction is not None 285 self.node.handlemessage( 286 'impulse', 287 msg.pos[0], 288 msg.pos[1], 289 msg.pos[2], 290 msg.velocity[0], 291 msg.velocity[1], 292 msg.velocity[2], 293 1.0 * msg.magnitude, 294 1.0 * msg.velocity_magnitude, 295 msg.radius, 296 0, 297 msg.force_direction[0], 298 msg.force_direction[1], 299 msg.force_direction[2], 300 ) 301 else: 302 super().handlemessage(msg)
A lovely egg that can be picked up for points.
245 def __init__(self, position: tuple[float, float, float] = (0.0, 1.0, 0.0)): 246 super().__init__() 247 activity = self.activity 248 assert isinstance(activity, EasterEggHuntGame) 249 shared = SharedObjects.get() 250 251 # Spawn just above the provided point. 252 self._spawn_pos = (position[0], position[1] + 1.0, position[2]) 253 ctex = (activity.egg_tex_1, activity.egg_tex_2, activity.egg_tex_3)[ 254 random.randrange(3) 255 ] 256 mats = [shared.object_material, activity.egg_material] 257 self.node = bs.newnode( 258 'prop', 259 delegate=self, 260 attrs={ 261 'mesh': activity.egg_mesh, 262 'color_texture': ctex, 263 'body': 'capsule', 264 'reflection': 'soft', 265 'mesh_scale': 0.5, 266 'body_scale': 0.6, 267 'density': 4.0, 268 'reflection_scale': [0.15], 269 'shadow_size': 0.6, 270 'position': self._spawn_pos, 271 'materials': mats, 272 }, 273 )
Instantiates an Actor in the current bascenev1.Activity.
Returns whether the Actor is still present in a meaningful way.
Note that a dying character should still return True here as long as their corpse is visible; this is about presence, not being 'alive' (see bascenev1.Actor.is_alive() for that).
If this returns False, it is assumed the Actor can be completely deleted without affecting the game; this call is often used when pruning lists of Actors, such as with bascenev1.Actor.autoretain()
The default implementation of this method always return True.
Note that the boolean operator for the Actor class calls this method, so a simple "if myactor" test will conveniently do the right thing even if myactor is set to None.
278 def handlemessage(self, msg: Any) -> Any: 279 if isinstance(msg, bs.DieMessage): 280 if self.node: 281 self.node.delete() 282 elif isinstance(msg, bs.HitMessage): 283 if self.node: 284 assert msg.force_direction is not None 285 self.node.handlemessage( 286 'impulse', 287 msg.pos[0], 288 msg.pos[1], 289 msg.pos[2], 290 msg.velocity[0], 291 msg.velocity[1], 292 msg.velocity[2], 293 1.0 * msg.magnitude, 294 1.0 * msg.velocity_magnitude, 295 msg.radius, 296 0, 297 msg.force_direction[0], 298 msg.force_direction[1], 299 msg.force_direction[2], 300 ) 301 else: 302 super().handlemessage(msg)
General message handling; can be passed any message object.
Inherited Members
- bascenev1._actor.Actor
- autoretain
- on_expire
- expired
- is_alive
- activity
- getactivity