bastd.actor.spazfactory
Provides a factory object from creating Spazzes.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides a factory object from creating Spazzes.""" 4 5from __future__ import annotations 6 7from typing import TYPE_CHECKING 8 9import ba 10import ba.internal 11from bastd.gameutils import SharedObjects 12 13if TYPE_CHECKING: 14 from typing import Any, Sequence 15 16 17class SpazFactory: 18 """Wraps up media and other resources used by ba.Spaz instances. 19 20 Category: **Gameplay Classes** 21 22 Generally one of these is created per ba.Activity and shared 23 between all spaz instances. Use ba.Spaz.get_factory() to return 24 the shared factory for the current activity. 25 """ 26 27 impact_sounds_medium: Sequence[ba.Sound] 28 """A tuple of ba.Sound-s for when a ba.Spaz hits something kinda hard.""" 29 30 impact_sounds_hard: Sequence[ba.Sound] 31 """A tuple of ba.Sound-s for when a ba.Spaz hits something really hard.""" 32 33 impact_sounds_harder: Sequence[ba.Sound] 34 """A tuple of ba.Sound-s for when a ba.Spaz hits something really 35 really hard.""" 36 37 single_player_death_sound: ba.Sound 38 """The sound that plays for an 'important' spaz death such as in 39 co-op games.""" 40 41 punch_sound_weak: ba.Sound 42 """A weak punch ba.Sound.""" 43 44 punch_sound: ba.Sound 45 """A standard punch ba.Sound.""" 46 47 punch_sound_strong: Sequence[ba.Sound] 48 """A tuple of stronger sounding punch ba.Sounds.""" 49 50 punch_sound_stronger: ba.Sound 51 """A really really strong sounding punch ba.Sound.""" 52 53 swish_sound: ba.Sound 54 """A punch swish ba.Sound.""" 55 56 block_sound: ba.Sound 57 """A ba.Sound for when an attack is blocked by invincibility.""" 58 59 shatter_sound: ba.Sound 60 """A ba.Sound for when a frozen ba.Spaz shatters.""" 61 62 splatter_sound: ba.Sound 63 """A ba.Sound for when a ba.Spaz blows up via curse.""" 64 65 spaz_material: ba.Material 66 """A ba.Material applied to all of parts of a ba.Spaz.""" 67 68 roller_material: ba.Material 69 """A ba.Material applied to the invisible roller ball body that 70 a ba.Spaz uses for locomotion.""" 71 72 punch_material: ba.Material 73 """A ba.Material applied to the 'fist' of a ba.Spaz.""" 74 75 pickup_material: ba.Material 76 """A ba.Material applied to the 'grabber' body of a ba.Spaz.""" 77 78 curse_material: ba.Material 79 """A ba.Material applied to a cursed ba.Spaz that triggers an explosion.""" 80 81 _STORENAME = ba.storagename() 82 83 def _preload(self, character: str) -> None: 84 """Preload media needed for a given character.""" 85 self.get_media(character) 86 87 def __init__(self) -> None: 88 """Instantiate a factory object.""" 89 # pylint: disable=cyclic-import 90 # FIXME: should probably put these somewhere common so we don't 91 # have to import them from a module that imports us. 92 from bastd.actor.spaz import ( 93 PickupMessage, 94 PunchHitMessage, 95 CurseExplodeMessage, 96 ) 97 98 shared = SharedObjects.get() 99 self.impact_sounds_medium = ( 100 ba.getsound('impactMedium'), 101 ba.getsound('impactMedium2'), 102 ) 103 self.impact_sounds_hard = ( 104 ba.getsound('impactHard'), 105 ba.getsound('impactHard2'), 106 ba.getsound('impactHard3'), 107 ) 108 self.impact_sounds_harder = ( 109 ba.getsound('bigImpact'), 110 ba.getsound('bigImpact2'), 111 ) 112 self.single_player_death_sound = ba.getsound('playerDeath') 113 self.punch_sound_weak = ba.getsound('punchWeak01') 114 self.punch_sound = ba.getsound('punch01') 115 self.punch_sound_strong = ( 116 ba.getsound('punchStrong01'), 117 ba.getsound('punchStrong02'), 118 ) 119 self.punch_sound_stronger = ba.getsound('superPunch') 120 self.swish_sound = ba.getsound('punchSwish') 121 self.block_sound = ba.getsound('block') 122 self.shatter_sound = ba.getsound('shatter') 123 self.splatter_sound = ba.getsound('splatter') 124 self.spaz_material = ba.Material() 125 self.roller_material = ba.Material() 126 self.punch_material = ba.Material() 127 self.pickup_material = ba.Material() 128 self.curse_material = ba.Material() 129 130 footing_material = shared.footing_material 131 object_material = shared.object_material 132 player_material = shared.player_material 133 region_material = shared.region_material 134 135 # Send footing messages to spazzes so they know when they're on 136 # solid ground. 137 # Eww; this probably should just be built into the spaz node. 138 self.roller_material.add_actions( 139 conditions=('they_have_material', footing_material), 140 actions=( 141 ('message', 'our_node', 'at_connect', 'footing', 1), 142 ('message', 'our_node', 'at_disconnect', 'footing', -1), 143 ), 144 ) 145 146 self.spaz_material.add_actions( 147 conditions=('they_have_material', footing_material), 148 actions=( 149 ('message', 'our_node', 'at_connect', 'footing', 1), 150 ('message', 'our_node', 'at_disconnect', 'footing', -1), 151 ), 152 ) 153 154 # Punches. 155 self.punch_material.add_actions( 156 conditions=('they_are_different_node_than_us',), 157 actions=( 158 ('modify_part_collision', 'collide', True), 159 ('modify_part_collision', 'physical', False), 160 ('message', 'our_node', 'at_connect', PunchHitMessage()), 161 ), 162 ) 163 164 # Pickups. 165 self.pickup_material.add_actions( 166 conditions=( 167 ('they_are_different_node_than_us',), 168 'and', 169 ('they_have_material', object_material), 170 ), 171 actions=( 172 ('modify_part_collision', 'collide', True), 173 ('modify_part_collision', 'physical', False), 174 ('message', 'our_node', 'at_connect', PickupMessage()), 175 ), 176 ) 177 178 # Curse. 179 self.curse_material.add_actions( 180 conditions=( 181 ('they_are_different_node_than_us',), 182 'and', 183 ('they_have_material', player_material), 184 ), 185 actions=( 186 'message', 187 'our_node', 188 'at_connect', 189 CurseExplodeMessage(), 190 ), 191 ) 192 193 self.foot_impact_sounds = ( 194 ba.getsound('footImpact01'), 195 ba.getsound('footImpact02'), 196 ba.getsound('footImpact03'), 197 ) 198 199 self.foot_skid_sound = ba.getsound('skid01') 200 self.foot_roll_sound = ba.getsound('scamper01') 201 202 self.roller_material.add_actions( 203 conditions=('they_have_material', footing_material), 204 actions=( 205 ('impact_sound', self.foot_impact_sounds, 1, 0.2), 206 ('skid_sound', self.foot_skid_sound, 20, 0.3), 207 ('roll_sound', self.foot_roll_sound, 20, 3.0), 208 ), 209 ) 210 211 self.skid_sound = ba.getsound('gravelSkid') 212 213 self.spaz_material.add_actions( 214 conditions=('they_have_material', footing_material), 215 actions=( 216 ('impact_sound', self.foot_impact_sounds, 20, 6), 217 ('skid_sound', self.skid_sound, 2.0, 1), 218 ('roll_sound', self.skid_sound, 2.0, 1), 219 ), 220 ) 221 222 self.shield_up_sound = ba.getsound('shieldUp') 223 self.shield_down_sound = ba.getsound('shieldDown') 224 self.shield_hit_sound = ba.getsound('shieldHit') 225 226 # We don't want to collide with stuff we're initially overlapping 227 # (unless its marked with a special region material). 228 self.spaz_material.add_actions( 229 conditions=( 230 ( 231 ('we_are_younger_than', 51), 232 'and', 233 ('they_are_different_node_than_us',), 234 ), 235 'and', 236 ('they_dont_have_material', region_material), 237 ), 238 actions=('modify_node_collision', 'collide', False), 239 ) 240 241 self.spaz_media: dict[str, Any] = {} 242 243 # Lets load some basic rules. 244 # (allows them to be tweaked from the master server) 245 self.shield_decay_rate = ba.internal.get_v1_account_misc_read_val( 246 'rsdr', 10.0 247 ) 248 self.punch_cooldown = ba.internal.get_v1_account_misc_read_val( 249 'rpc', 400 250 ) 251 self.punch_cooldown_gloves = ba.internal.get_v1_account_misc_read_val( 252 'rpcg', 300 253 ) 254 self.punch_power_scale = ba.internal.get_v1_account_misc_read_val( 255 'rpp', 1.2 256 ) 257 self.punch_power_scale_gloves = ( 258 ba.internal.get_v1_account_misc_read_val('rppg', 1.4) 259 ) 260 self.max_shield_spillover_damage = ( 261 ba.internal.get_v1_account_misc_read_val('rsms', 500) 262 ) 263 264 def get_style(self, character: str) -> str: 265 """Return the named style for this character. 266 267 (this influences subtle aspects of their appearance, etc) 268 """ 269 return ba.app.spaz_appearances[character].style 270 271 def get_media(self, character: str) -> dict[str, Any]: 272 """Return the set of media used by this variant of spaz.""" 273 char = ba.app.spaz_appearances[character] 274 if character not in self.spaz_media: 275 media = self.spaz_media[character] = { 276 'jump_sounds': [ba.getsound(s) for s in char.jump_sounds], 277 'attack_sounds': [ba.getsound(s) for s in char.attack_sounds], 278 'impact_sounds': [ba.getsound(s) for s in char.impact_sounds], 279 'death_sounds': [ba.getsound(s) for s in char.death_sounds], 280 'pickup_sounds': [ba.getsound(s) for s in char.pickup_sounds], 281 'fall_sounds': [ba.getsound(s) for s in char.fall_sounds], 282 'color_texture': ba.gettexture(char.color_texture), 283 'color_mask_texture': ba.gettexture(char.color_mask_texture), 284 'head_model': ba.getmodel(char.head_model), 285 'torso_model': ba.getmodel(char.torso_model), 286 'pelvis_model': ba.getmodel(char.pelvis_model), 287 'upper_arm_model': ba.getmodel(char.upper_arm_model), 288 'forearm_model': ba.getmodel(char.forearm_model), 289 'hand_model': ba.getmodel(char.hand_model), 290 'upper_leg_model': ba.getmodel(char.upper_leg_model), 291 'lower_leg_model': ba.getmodel(char.lower_leg_model), 292 'toes_model': ba.getmodel(char.toes_model), 293 } 294 else: 295 media = self.spaz_media[character] 296 return media 297 298 @classmethod 299 def get(cls) -> SpazFactory: 300 """Return the shared ba.SpazFactory, creating it if necessary.""" 301 # pylint: disable=cyclic-import 302 activity = ba.getactivity() 303 factory = activity.customdata.get(cls._STORENAME) 304 if factory is None: 305 factory = activity.customdata[cls._STORENAME] = SpazFactory() 306 assert isinstance(factory, SpazFactory) 307 return factory
18class SpazFactory: 19 """Wraps up media and other resources used by ba.Spaz instances. 20 21 Category: **Gameplay Classes** 22 23 Generally one of these is created per ba.Activity and shared 24 between all spaz instances. Use ba.Spaz.get_factory() to return 25 the shared factory for the current activity. 26 """ 27 28 impact_sounds_medium: Sequence[ba.Sound] 29 """A tuple of ba.Sound-s for when a ba.Spaz hits something kinda hard.""" 30 31 impact_sounds_hard: Sequence[ba.Sound] 32 """A tuple of ba.Sound-s for when a ba.Spaz hits something really hard.""" 33 34 impact_sounds_harder: Sequence[ba.Sound] 35 """A tuple of ba.Sound-s for when a ba.Spaz hits something really 36 really hard.""" 37 38 single_player_death_sound: ba.Sound 39 """The sound that plays for an 'important' spaz death such as in 40 co-op games.""" 41 42 punch_sound_weak: ba.Sound 43 """A weak punch ba.Sound.""" 44 45 punch_sound: ba.Sound 46 """A standard punch ba.Sound.""" 47 48 punch_sound_strong: Sequence[ba.Sound] 49 """A tuple of stronger sounding punch ba.Sounds.""" 50 51 punch_sound_stronger: ba.Sound 52 """A really really strong sounding punch ba.Sound.""" 53 54 swish_sound: ba.Sound 55 """A punch swish ba.Sound.""" 56 57 block_sound: ba.Sound 58 """A ba.Sound for when an attack is blocked by invincibility.""" 59 60 shatter_sound: ba.Sound 61 """A ba.Sound for when a frozen ba.Spaz shatters.""" 62 63 splatter_sound: ba.Sound 64 """A ba.Sound for when a ba.Spaz blows up via curse.""" 65 66 spaz_material: ba.Material 67 """A ba.Material applied to all of parts of a ba.Spaz.""" 68 69 roller_material: ba.Material 70 """A ba.Material applied to the invisible roller ball body that 71 a ba.Spaz uses for locomotion.""" 72 73 punch_material: ba.Material 74 """A ba.Material applied to the 'fist' of a ba.Spaz.""" 75 76 pickup_material: ba.Material 77 """A ba.Material applied to the 'grabber' body of a ba.Spaz.""" 78 79 curse_material: ba.Material 80 """A ba.Material applied to a cursed ba.Spaz that triggers an explosion.""" 81 82 _STORENAME = ba.storagename() 83 84 def _preload(self, character: str) -> None: 85 """Preload media needed for a given character.""" 86 self.get_media(character) 87 88 def __init__(self) -> None: 89 """Instantiate a factory object.""" 90 # pylint: disable=cyclic-import 91 # FIXME: should probably put these somewhere common so we don't 92 # have to import them from a module that imports us. 93 from bastd.actor.spaz import ( 94 PickupMessage, 95 PunchHitMessage, 96 CurseExplodeMessage, 97 ) 98 99 shared = SharedObjects.get() 100 self.impact_sounds_medium = ( 101 ba.getsound('impactMedium'), 102 ba.getsound('impactMedium2'), 103 ) 104 self.impact_sounds_hard = ( 105 ba.getsound('impactHard'), 106 ba.getsound('impactHard2'), 107 ba.getsound('impactHard3'), 108 ) 109 self.impact_sounds_harder = ( 110 ba.getsound('bigImpact'), 111 ba.getsound('bigImpact2'), 112 ) 113 self.single_player_death_sound = ba.getsound('playerDeath') 114 self.punch_sound_weak = ba.getsound('punchWeak01') 115 self.punch_sound = ba.getsound('punch01') 116 self.punch_sound_strong = ( 117 ba.getsound('punchStrong01'), 118 ba.getsound('punchStrong02'), 119 ) 120 self.punch_sound_stronger = ba.getsound('superPunch') 121 self.swish_sound = ba.getsound('punchSwish') 122 self.block_sound = ba.getsound('block') 123 self.shatter_sound = ba.getsound('shatter') 124 self.splatter_sound = ba.getsound('splatter') 125 self.spaz_material = ba.Material() 126 self.roller_material = ba.Material() 127 self.punch_material = ba.Material() 128 self.pickup_material = ba.Material() 129 self.curse_material = ba.Material() 130 131 footing_material = shared.footing_material 132 object_material = shared.object_material 133 player_material = shared.player_material 134 region_material = shared.region_material 135 136 # Send footing messages to spazzes so they know when they're on 137 # solid ground. 138 # Eww; this probably should just be built into the spaz node. 139 self.roller_material.add_actions( 140 conditions=('they_have_material', footing_material), 141 actions=( 142 ('message', 'our_node', 'at_connect', 'footing', 1), 143 ('message', 'our_node', 'at_disconnect', 'footing', -1), 144 ), 145 ) 146 147 self.spaz_material.add_actions( 148 conditions=('they_have_material', footing_material), 149 actions=( 150 ('message', 'our_node', 'at_connect', 'footing', 1), 151 ('message', 'our_node', 'at_disconnect', 'footing', -1), 152 ), 153 ) 154 155 # Punches. 156 self.punch_material.add_actions( 157 conditions=('they_are_different_node_than_us',), 158 actions=( 159 ('modify_part_collision', 'collide', True), 160 ('modify_part_collision', 'physical', False), 161 ('message', 'our_node', 'at_connect', PunchHitMessage()), 162 ), 163 ) 164 165 # Pickups. 166 self.pickup_material.add_actions( 167 conditions=( 168 ('they_are_different_node_than_us',), 169 'and', 170 ('they_have_material', object_material), 171 ), 172 actions=( 173 ('modify_part_collision', 'collide', True), 174 ('modify_part_collision', 'physical', False), 175 ('message', 'our_node', 'at_connect', PickupMessage()), 176 ), 177 ) 178 179 # Curse. 180 self.curse_material.add_actions( 181 conditions=( 182 ('they_are_different_node_than_us',), 183 'and', 184 ('they_have_material', player_material), 185 ), 186 actions=( 187 'message', 188 'our_node', 189 'at_connect', 190 CurseExplodeMessage(), 191 ), 192 ) 193 194 self.foot_impact_sounds = ( 195 ba.getsound('footImpact01'), 196 ba.getsound('footImpact02'), 197 ba.getsound('footImpact03'), 198 ) 199 200 self.foot_skid_sound = ba.getsound('skid01') 201 self.foot_roll_sound = ba.getsound('scamper01') 202 203 self.roller_material.add_actions( 204 conditions=('they_have_material', footing_material), 205 actions=( 206 ('impact_sound', self.foot_impact_sounds, 1, 0.2), 207 ('skid_sound', self.foot_skid_sound, 20, 0.3), 208 ('roll_sound', self.foot_roll_sound, 20, 3.0), 209 ), 210 ) 211 212 self.skid_sound = ba.getsound('gravelSkid') 213 214 self.spaz_material.add_actions( 215 conditions=('they_have_material', footing_material), 216 actions=( 217 ('impact_sound', self.foot_impact_sounds, 20, 6), 218 ('skid_sound', self.skid_sound, 2.0, 1), 219 ('roll_sound', self.skid_sound, 2.0, 1), 220 ), 221 ) 222 223 self.shield_up_sound = ba.getsound('shieldUp') 224 self.shield_down_sound = ba.getsound('shieldDown') 225 self.shield_hit_sound = ba.getsound('shieldHit') 226 227 # We don't want to collide with stuff we're initially overlapping 228 # (unless its marked with a special region material). 229 self.spaz_material.add_actions( 230 conditions=( 231 ( 232 ('we_are_younger_than', 51), 233 'and', 234 ('they_are_different_node_than_us',), 235 ), 236 'and', 237 ('they_dont_have_material', region_material), 238 ), 239 actions=('modify_node_collision', 'collide', False), 240 ) 241 242 self.spaz_media: dict[str, Any] = {} 243 244 # Lets load some basic rules. 245 # (allows them to be tweaked from the master server) 246 self.shield_decay_rate = ba.internal.get_v1_account_misc_read_val( 247 'rsdr', 10.0 248 ) 249 self.punch_cooldown = ba.internal.get_v1_account_misc_read_val( 250 'rpc', 400 251 ) 252 self.punch_cooldown_gloves = ba.internal.get_v1_account_misc_read_val( 253 'rpcg', 300 254 ) 255 self.punch_power_scale = ba.internal.get_v1_account_misc_read_val( 256 'rpp', 1.2 257 ) 258 self.punch_power_scale_gloves = ( 259 ba.internal.get_v1_account_misc_read_val('rppg', 1.4) 260 ) 261 self.max_shield_spillover_damage = ( 262 ba.internal.get_v1_account_misc_read_val('rsms', 500) 263 ) 264 265 def get_style(self, character: str) -> str: 266 """Return the named style for this character. 267 268 (this influences subtle aspects of their appearance, etc) 269 """ 270 return ba.app.spaz_appearances[character].style 271 272 def get_media(self, character: str) -> dict[str, Any]: 273 """Return the set of media used by this variant of spaz.""" 274 char = ba.app.spaz_appearances[character] 275 if character not in self.spaz_media: 276 media = self.spaz_media[character] = { 277 'jump_sounds': [ba.getsound(s) for s in char.jump_sounds], 278 'attack_sounds': [ba.getsound(s) for s in char.attack_sounds], 279 'impact_sounds': [ba.getsound(s) for s in char.impact_sounds], 280 'death_sounds': [ba.getsound(s) for s in char.death_sounds], 281 'pickup_sounds': [ba.getsound(s) for s in char.pickup_sounds], 282 'fall_sounds': [ba.getsound(s) for s in char.fall_sounds], 283 'color_texture': ba.gettexture(char.color_texture), 284 'color_mask_texture': ba.gettexture(char.color_mask_texture), 285 'head_model': ba.getmodel(char.head_model), 286 'torso_model': ba.getmodel(char.torso_model), 287 'pelvis_model': ba.getmodel(char.pelvis_model), 288 'upper_arm_model': ba.getmodel(char.upper_arm_model), 289 'forearm_model': ba.getmodel(char.forearm_model), 290 'hand_model': ba.getmodel(char.hand_model), 291 'upper_leg_model': ba.getmodel(char.upper_leg_model), 292 'lower_leg_model': ba.getmodel(char.lower_leg_model), 293 'toes_model': ba.getmodel(char.toes_model), 294 } 295 else: 296 media = self.spaz_media[character] 297 return media 298 299 @classmethod 300 def get(cls) -> SpazFactory: 301 """Return the shared ba.SpazFactory, creating it if necessary.""" 302 # pylint: disable=cyclic-import 303 activity = ba.getactivity() 304 factory = activity.customdata.get(cls._STORENAME) 305 if factory is None: 306 factory = activity.customdata[cls._STORENAME] = SpazFactory() 307 assert isinstance(factory, SpazFactory) 308 return factory
Wraps up media and other resources used by ba.Spaz instances.
Category: Gameplay Classes
Generally one of these is created per ba.Activity and shared between all spaz instances. Use ba.Spaz.get_factory() to return the shared factory for the current activity.
88 def __init__(self) -> None: 89 """Instantiate a factory object.""" 90 # pylint: disable=cyclic-import 91 # FIXME: should probably put these somewhere common so we don't 92 # have to import them from a module that imports us. 93 from bastd.actor.spaz import ( 94 PickupMessage, 95 PunchHitMessage, 96 CurseExplodeMessage, 97 ) 98 99 shared = SharedObjects.get() 100 self.impact_sounds_medium = ( 101 ba.getsound('impactMedium'), 102 ba.getsound('impactMedium2'), 103 ) 104 self.impact_sounds_hard = ( 105 ba.getsound('impactHard'), 106 ba.getsound('impactHard2'), 107 ba.getsound('impactHard3'), 108 ) 109 self.impact_sounds_harder = ( 110 ba.getsound('bigImpact'), 111 ba.getsound('bigImpact2'), 112 ) 113 self.single_player_death_sound = ba.getsound('playerDeath') 114 self.punch_sound_weak = ba.getsound('punchWeak01') 115 self.punch_sound = ba.getsound('punch01') 116 self.punch_sound_strong = ( 117 ba.getsound('punchStrong01'), 118 ba.getsound('punchStrong02'), 119 ) 120 self.punch_sound_stronger = ba.getsound('superPunch') 121 self.swish_sound = ba.getsound('punchSwish') 122 self.block_sound = ba.getsound('block') 123 self.shatter_sound = ba.getsound('shatter') 124 self.splatter_sound = ba.getsound('splatter') 125 self.spaz_material = ba.Material() 126 self.roller_material = ba.Material() 127 self.punch_material = ba.Material() 128 self.pickup_material = ba.Material() 129 self.curse_material = ba.Material() 130 131 footing_material = shared.footing_material 132 object_material = shared.object_material 133 player_material = shared.player_material 134 region_material = shared.region_material 135 136 # Send footing messages to spazzes so they know when they're on 137 # solid ground. 138 # Eww; this probably should just be built into the spaz node. 139 self.roller_material.add_actions( 140 conditions=('they_have_material', footing_material), 141 actions=( 142 ('message', 'our_node', 'at_connect', 'footing', 1), 143 ('message', 'our_node', 'at_disconnect', 'footing', -1), 144 ), 145 ) 146 147 self.spaz_material.add_actions( 148 conditions=('they_have_material', footing_material), 149 actions=( 150 ('message', 'our_node', 'at_connect', 'footing', 1), 151 ('message', 'our_node', 'at_disconnect', 'footing', -1), 152 ), 153 ) 154 155 # Punches. 156 self.punch_material.add_actions( 157 conditions=('they_are_different_node_than_us',), 158 actions=( 159 ('modify_part_collision', 'collide', True), 160 ('modify_part_collision', 'physical', False), 161 ('message', 'our_node', 'at_connect', PunchHitMessage()), 162 ), 163 ) 164 165 # Pickups. 166 self.pickup_material.add_actions( 167 conditions=( 168 ('they_are_different_node_than_us',), 169 'and', 170 ('they_have_material', object_material), 171 ), 172 actions=( 173 ('modify_part_collision', 'collide', True), 174 ('modify_part_collision', 'physical', False), 175 ('message', 'our_node', 'at_connect', PickupMessage()), 176 ), 177 ) 178 179 # Curse. 180 self.curse_material.add_actions( 181 conditions=( 182 ('they_are_different_node_than_us',), 183 'and', 184 ('they_have_material', player_material), 185 ), 186 actions=( 187 'message', 188 'our_node', 189 'at_connect', 190 CurseExplodeMessage(), 191 ), 192 ) 193 194 self.foot_impact_sounds = ( 195 ba.getsound('footImpact01'), 196 ba.getsound('footImpact02'), 197 ba.getsound('footImpact03'), 198 ) 199 200 self.foot_skid_sound = ba.getsound('skid01') 201 self.foot_roll_sound = ba.getsound('scamper01') 202 203 self.roller_material.add_actions( 204 conditions=('they_have_material', footing_material), 205 actions=( 206 ('impact_sound', self.foot_impact_sounds, 1, 0.2), 207 ('skid_sound', self.foot_skid_sound, 20, 0.3), 208 ('roll_sound', self.foot_roll_sound, 20, 3.0), 209 ), 210 ) 211 212 self.skid_sound = ba.getsound('gravelSkid') 213 214 self.spaz_material.add_actions( 215 conditions=('they_have_material', footing_material), 216 actions=( 217 ('impact_sound', self.foot_impact_sounds, 20, 6), 218 ('skid_sound', self.skid_sound, 2.0, 1), 219 ('roll_sound', self.skid_sound, 2.0, 1), 220 ), 221 ) 222 223 self.shield_up_sound = ba.getsound('shieldUp') 224 self.shield_down_sound = ba.getsound('shieldDown') 225 self.shield_hit_sound = ba.getsound('shieldHit') 226 227 # We don't want to collide with stuff we're initially overlapping 228 # (unless its marked with a special region material). 229 self.spaz_material.add_actions( 230 conditions=( 231 ( 232 ('we_are_younger_than', 51), 233 'and', 234 ('they_are_different_node_than_us',), 235 ), 236 'and', 237 ('they_dont_have_material', region_material), 238 ), 239 actions=('modify_node_collision', 'collide', False), 240 ) 241 242 self.spaz_media: dict[str, Any] = {} 243 244 # Lets load some basic rules. 245 # (allows them to be tweaked from the master server) 246 self.shield_decay_rate = ba.internal.get_v1_account_misc_read_val( 247 'rsdr', 10.0 248 ) 249 self.punch_cooldown = ba.internal.get_v1_account_misc_read_val( 250 'rpc', 400 251 ) 252 self.punch_cooldown_gloves = ba.internal.get_v1_account_misc_read_val( 253 'rpcg', 300 254 ) 255 self.punch_power_scale = ba.internal.get_v1_account_misc_read_val( 256 'rpp', 1.2 257 ) 258 self.punch_power_scale_gloves = ( 259 ba.internal.get_v1_account_misc_read_val('rppg', 1.4) 260 ) 261 self.max_shield_spillover_damage = ( 262 ba.internal.get_v1_account_misc_read_val('rsms', 500) 263 )
Instantiate a factory object.
A tuple of ba.Sound-s for when a ba.Spaz hits something kinda hard.
A tuple of ba.Sound-s for when a ba.Spaz hits something really hard.
A tuple of ba.Sound-s for when a ba.Spaz hits something really really hard.
The sound that plays for an 'important' spaz death such as in co-op games.
A ba.Material applied to the invisible roller ball body that a ba.Spaz uses for locomotion.
265 def get_style(self, character: str) -> str: 266 """Return the named style for this character. 267 268 (this influences subtle aspects of their appearance, etc) 269 """ 270 return ba.app.spaz_appearances[character].style
Return the named style for this character.
(this influences subtle aspects of their appearance, etc)
272 def get_media(self, character: str) -> dict[str, Any]: 273 """Return the set of media used by this variant of spaz.""" 274 char = ba.app.spaz_appearances[character] 275 if character not in self.spaz_media: 276 media = self.spaz_media[character] = { 277 'jump_sounds': [ba.getsound(s) for s in char.jump_sounds], 278 'attack_sounds': [ba.getsound(s) for s in char.attack_sounds], 279 'impact_sounds': [ba.getsound(s) for s in char.impact_sounds], 280 'death_sounds': [ba.getsound(s) for s in char.death_sounds], 281 'pickup_sounds': [ba.getsound(s) for s in char.pickup_sounds], 282 'fall_sounds': [ba.getsound(s) for s in char.fall_sounds], 283 'color_texture': ba.gettexture(char.color_texture), 284 'color_mask_texture': ba.gettexture(char.color_mask_texture), 285 'head_model': ba.getmodel(char.head_model), 286 'torso_model': ba.getmodel(char.torso_model), 287 'pelvis_model': ba.getmodel(char.pelvis_model), 288 'upper_arm_model': ba.getmodel(char.upper_arm_model), 289 'forearm_model': ba.getmodel(char.forearm_model), 290 'hand_model': ba.getmodel(char.hand_model), 291 'upper_leg_model': ba.getmodel(char.upper_leg_model), 292 'lower_leg_model': ba.getmodel(char.lower_leg_model), 293 'toes_model': ba.getmodel(char.toes_model), 294 } 295 else: 296 media = self.spaz_media[character] 297 return media
Return the set of media used by this variant of spaz.
299 @classmethod 300 def get(cls) -> SpazFactory: 301 """Return the shared ba.SpazFactory, creating it if necessary.""" 302 # pylint: disable=cyclic-import 303 activity = ba.getactivity() 304 factory = activity.customdata.get(cls._STORENAME) 305 if factory is None: 306 factory = activity.customdata[cls._STORENAME] = SpazFactory() 307 assert isinstance(factory, SpazFactory) 308 return factory
Return the shared ba.SpazFactory, creating it if necessary.