Cleaning up factory classes

This commit is contained in:
Eric Froemling 2020-06-18 12:41:30 -07:00
parent c5b0d977e3
commit bc22359dcd
8 changed files with 68 additions and 64 deletions

View File

@ -34,10 +34,6 @@ from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, Sequence, Optional, Callable, List, Tuple, Type
# Attr we store these objects as on the current activity.
# (based on our module so hopefully avoids conflicts)
STORAGE_ATTR_NAME = '_' + __name__.replace('.', '_') + '_bombfactory'
PlayerType = TypeVar('PlayerType', bound='ba.Player')
@ -150,14 +146,16 @@ class BombFactory:
ba.Sound for a rolling bomb.
"""
@staticmethod
def get() -> BombFactory:
_STORENAME = ba.storagename()
@classmethod
def get(cls) -> BombFactory:
"""Get/create a shared bastd.actor.bomb.BombFactory object."""
activity = ba.getactivity()
factory = getattr(activity, STORAGE_ATTR_NAME, None)
factory = activity.customdata.get(cls._STORENAME)
if factory is None:
factory = BombFactory()
setattr(activity, STORAGE_ATTR_NAME, factory)
activity.customdata[cls._STORENAME] = factory
assert isinstance(factory, BombFactory)
return factory

View File

@ -59,6 +59,8 @@ class FlagFactory:
The ba.Texture for flags.
"""
_STORENAME = ba.storagename()
def __init__(self) -> None:
"""Instantiate a FlagFactory.
@ -123,14 +125,14 @@ class FlagFactory:
self.flag_texture = ba.gettexture('flagColor')
@staticmethod
def get() -> FlagFactory:
@classmethod
def get(cls) -> FlagFactory:
"""Get/create a shared FlagFactory instance."""
activity = ba.getactivity()
factory = getattr(activity, 'shared_flag_factory', None)
factory = activity.customdata.get(cls._STORENAME)
if factory is None:
factory = FlagFactory()
setattr(activity, 'shared_flag_factory', factory)
activity.customdata[cls._STORENAME] = factory
assert isinstance(factory, FlagFactory)
return factory

View File

@ -29,6 +29,7 @@ from typing import TYPE_CHECKING
import ba
from bastd.actor import bomb as stdbomb
from bastd.actor.powerupbox import PowerupBoxFactory
from bastd.actor.spazfactory import SpazFactory
from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
@ -56,18 +57,6 @@ class BombDiedMessage:
"""A bomb has died and thus can be recycled."""
def get_factory() -> SpazFactory:
"""Return the shared ba.SpazFactory object, creating it if necessary."""
# pylint: disable=cyclic-import
from bastd.actor.spazfactory import SpazFactory
activity = ba.getactivity()
factory = getattr(activity, 'shared_spaz_factory', None)
if factory is None:
factory = activity.shared_spaz_factory = SpazFactory() # type: ignore
assert isinstance(factory, SpazFactory)
return factory
class Spaz(ba.Actor):
"""
Base class for various Spazzes.
@ -112,7 +101,7 @@ class Spaz(ba.Actor):
shared = SharedObjects.get()
activity = self.activity
factory = get_factory()
factory = SpazFactory.get()
# we need to behave slightly different in the tutorial
self._demo_mode = demo_mode
@ -466,7 +455,7 @@ class Spaz(ba.Actor):
ba.timer(
0.1,
ba.WeakCall(self._safe_play_sound,
get_factory().swish_sound, 0.8))
SpazFactory.get().swish_sound, 0.8))
self._turbo_filter_add_press('punch')
def _safe_play_sound(self, sound: ba.Sound, volume: float) -> None:
@ -605,7 +594,7 @@ class Spaz(ba.Actor):
he will explode in 5 seconds.
"""
if not self._cursed:
factory = get_factory()
factory = SpazFactory.get()
self._cursed = True
# Add the curse material.
@ -637,7 +626,7 @@ class Spaz(ba.Actor):
self._punch_power_scale = 1.7
self._punch_cooldown = 300
else:
factory = get_factory()
factory = SpazFactory.get()
self._punch_power_scale = factory.punch_power_scale_gloves
self._punch_cooldown = factory.punch_cooldown_gloves
@ -650,7 +639,7 @@ class Spaz(ba.Actor):
ba.print_error('Can\'t equip shields; no node.')
return
factory = get_factory()
factory = SpazFactory.get()
if self.shield is None:
self.shield = ba.newnode('shield',
owner=self.node,
@ -685,7 +674,7 @@ class Spaz(ba.Actor):
self.shield = None
self.shield_decay_timer = None
assert self.node
ba.playsound(get_factory().shield_down_sound,
ba.playsound(SpazFactory.get().shield_down_sound,
1.0,
position=self.node.position)
else:
@ -802,7 +791,7 @@ class Spaz(ba.Actor):
ba.WeakCall(self._gloves_wear_off),
timeformat=ba.TimeFormat.MILLISECONDS))
elif msg.poweruptype == 'shield':
factory = get_factory()
factory = SpazFactory.get()
# Let's allow powerup-equipped shields to lose hp over time.
self.equip_shields(decay=factory.shield_decay_rate > 0)
@ -832,7 +821,7 @@ class Spaz(ba.Actor):
self._cursed = False
# Remove cursed material.
factory = get_factory()
factory = SpazFactory.get()
for attr in ['materials', 'roller_materials']:
materials = getattr(self.node, attr)
if factory.curse_material in materials:
@ -856,7 +845,7 @@ class Spaz(ba.Actor):
if not self.node:
return None
if self.node.invincible:
ba.playsound(get_factory().block_sound,
ba.playsound(SpazFactory.get().block_sound,
1.0,
position=self.node.position)
return None
@ -881,7 +870,7 @@ class Spaz(ba.Actor):
if not self.node:
return None
if self.node.invincible:
ba.playsound(get_factory().block_sound,
ba.playsound(SpazFactory.get().block_sound,
1.0,
position=self.node.position)
return True
@ -924,13 +913,13 @@ class Spaz(ba.Actor):
# without damaging the player.
# However, massive damage events should still be able to
# damage the player. This hopefully gives us a happy medium.
max_spillover = get_factory().max_shield_spillover_damage
max_spillover = SpazFactory.get().max_shield_spillover_damage
if self.shield_hitpoints <= 0:
# FIXME: Transition out perhaps?
self.shield.delete()
self.shield = None
ba.playsound(get_factory().shield_down_sound,
ba.playsound(SpazFactory.get().shield_down_sound,
1.0,
position=self.node.position)
@ -944,7 +933,7 @@ class Spaz(ba.Actor):
chunk_type='spark')
else:
ba.playsound(get_factory().shield_hit_sound,
ba.playsound(SpazFactory.get().shield_hit_sound,
0.5,
position=self.node.position)
@ -1001,14 +990,14 @@ class Spaz(ba.Actor):
# Let's always add in a super-punch sound with boxing
# gloves just to differentiate them.
if msg.hit_subtype == 'super_punch':
ba.playsound(get_factory().punch_sound_stronger,
ba.playsound(SpazFactory.get().punch_sound_stronger,
1.0,
position=self.node.position)
if damage > 500:
sounds = get_factory().punch_sound_strong
sounds = SpazFactory.get().punch_sound_strong
sound = sounds[random.randrange(len(sounds))]
else:
sound = get_factory().punch_sound
sound = SpazFactory.get().punch_sound
ba.playsound(sound, 1.0, position=self.node.position)
# Throw up some chunks.
@ -1118,7 +1107,7 @@ class Spaz(ba.Actor):
elif self.node:
self.node.hurt = 1.0
if self.play_big_death_sound and not wasdead:
ba.playsound(get_factory().single_player_death_sound)
ba.playsound(SpazFactory.get().single_player_death_sound)
self.node.dead = True
ba.timer(2.0, self.node.delete)
@ -1160,7 +1149,7 @@ class Spaz(ba.Actor):
# If its something besides another spaz, just do a muffled
# punch sound.
if node.getnodetype() != 'spaz':
sounds = get_factory().impact_sounds_medium
sounds = SpazFactory.get().impact_sounds_medium
sound = sounds[random.randrange(len(sounds))]
ba.playsound(sound, 1.0, position=self.node.position)
@ -1347,11 +1336,11 @@ class Spaz(ba.Actor):
scale=0.3,
spread=0.2,
chunk_type='ice')
ba.playsound(get_factory().shatter_sound,
ba.playsound(SpazFactory.get().shatter_sound,
1.0,
position=self.node.position)
else:
ba.playsound(get_factory().splatter_sound,
ba.playsound(SpazFactory.get().splatter_sound,
1.0,
position=self.node.position)
self.handlemessage(ba.DieMessage())
@ -1369,11 +1358,11 @@ class Spaz(ba.Actor):
self.node.handlemessage('knockout', max(0.0, 50.0 * intensity))
sounds: Sequence[ba.Sound]
if intensity > 5.0:
sounds = get_factory().impact_sounds_harder
sounds = SpazFactory.get().impact_sounds_harder
elif intensity > 3.0:
sounds = get_factory().impact_sounds_hard
sounds = SpazFactory.get().impact_sounds_hard
else:
sounds = get_factory().impact_sounds_medium
sounds = SpazFactory.get().impact_sounds_medium
sound = sounds[random.randrange(len(sounds))]
ba.playsound(sound, position=pos, volume=5.0)
@ -1418,7 +1407,7 @@ class Spaz(ba.Actor):
self._punch_power_scale = 1.2
self._punch_cooldown = BASE_PUNCH_COOLDOWN
else:
factory = get_factory()
factory = SpazFactory.get()
self._punch_power_scale = factory.punch_power_scale
self._punch_cooldown = factory.punch_cooldown
self._has_boxing_gloves = False

View File

@ -26,8 +26,6 @@ from typing import TYPE_CHECKING
import ba
from bastd.gameutils import SharedObjects
from bastd.actor.spaz import (PickupMessage, PunchHitMessage,
CurseExplodeMessage)
import _ba
if TYPE_CHECKING:
@ -97,12 +95,20 @@ class SpazFactory:
A ba.Material applied to a cursed ba.Spaz that triggers an explosion.
"""
_STORENAME = ba.storagename()
def _preload(self, character: str) -> None:
"""Preload media needed for a given character."""
self.get_media(character)
def __init__(self) -> None:
"""Instantiate a factory object."""
# pylint: disable=cyclic-import
# FIXME: should probably put these somewhere common so we don't
# have to import them from a module that imports us.
from bastd.actor.spaz import (PickupMessage, PunchHitMessage,
CurseExplodeMessage)
shared = SharedObjects.get()
self.impact_sounds_medium = (ba.getsound('impactMedium'),
ba.getsound('impactMedium2'))
@ -265,3 +271,14 @@ class SpazFactory:
else:
media = self.spaz_media[character]
return media
@classmethod
def get(cls) -> SpazFactory:
"""Return the shared ba.SpazFactory, creating it if necessary."""
# pylint: disable=cyclic-import
activity = ba.getactivity()
factory = activity.customdata.get(cls._STORENAME)
if factory is None:
factory = activity.customdata[cls._STORENAME] = SpazFactory()
assert isinstance(factory, SpazFactory)
return factory

View File

@ -28,7 +28,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING
import ba
from bastd.actor.spaz import get_factory
from bastd.actor.spazfactory import SpazFactory
from bastd.actor.scoreboard import Scoreboard
if TYPE_CHECKING:
@ -525,7 +525,7 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]):
# Play big death sound on our last death
# or for every one in solo mode.
if self._solo_mode or player.lives == 0:
ba.playsound(get_factory().single_player_death_sound)
ba.playsound(SpazFactory.get().single_player_death_sound)
# If we hit zero lives, we're dead (and our team might be too).
if player.lives == 0:

View File

@ -29,10 +29,6 @@ import ba
if TYPE_CHECKING:
from typing import Sequence, Optional
# Attr we store these objects as on the current activity.
# (based on our module so hopefully avoids conflicts)
STORAGE_ATTR_NAME = '_' + __name__.replace('.', '_') + '_sharedobjs'
class SharedObjects:
"""Various common components for use in games.
@ -44,9 +40,11 @@ class SharedObjects:
standard materials.
"""
_STORENAME = ba.storagename()
def __init__(self) -> None:
activity = ba.getactivity()
if hasattr(activity, STORAGE_ATTR_NAME):
if hasattr(activity, self._STORENAME):
raise RuntimeError('Use SharedObjects.get() to fetch the'
' shared instance for this activity.')
self._object_material: Optional[ba.Material] = None
@ -58,14 +56,14 @@ class SharedObjects:
self._region_material: Optional[ba.Material] = None
self._railing_material: Optional[ba.Material] = None
@staticmethod
def get() -> SharedObjects:
@classmethod
def get(cls) -> SharedObjects:
"""Fetch/create the instance of this class for the current activity."""
activity = ba.getactivity()
shobs = getattr(activity, STORAGE_ATTR_NAME, None)
shobs = activity.customdata.get(cls._STORENAME)
if shobs is None:
shobs = SharedObjects()
setattr(activity, STORAGE_ATTR_NAME, shobs)
activity.customdata[cls._STORENAME] = shobs
assert isinstance(shobs, SharedObjects)
return shobs

View File

@ -28,7 +28,6 @@ import weakref
from typing import TYPE_CHECKING
import ba
from bastd.actor import spaz
import _ba
if TYPE_CHECKING:
@ -886,6 +885,7 @@ def _preload2() -> None:
def _preload3() -> None:
from bastd.actor.spazfactory import SpazFactory
for mname in ['bomb', 'bombSticky', 'impactBomb']:
ba.getmodel(mname)
for tname in [
@ -895,7 +895,7 @@ def _preload3() -> None:
ba.gettexture(tname)
for sname in ['freeze', 'fuse01', 'activateBeep', 'warnBeep']:
ba.getsound(sname)
spaz.get_factory()
SpazFactory.get()
ba.timer(0.2, _preload4)

View File

@ -120,7 +120,7 @@ def get_target(path: str) -> None:
# Just expand it and it get placed wherever it belongs.
# Strangely, decompressing lots of these simultaneously leads to occasional
# "File does not exist" errors when running on Windows Subystem for Linux.
# "File does not exist" errors when running on Windows Subsystem for Linux.
# There should be no overlap in files getting written, but perhaps
# something about how tar rebuilds the directory structure causes clashes.
# It seems that just explicitly creating necessary directories first