source: nagslang/puzzle.py @ 328:14339d2d46bc

Last change on this file since 328:14339d2d46bc was 328:14339d2d46bc, checked in by Neil Muller <drnlmuller@…>, 7 years ago

Only add objects with actual puzzlers to the glue

File size: 3.1 KB
Line 
1from nagslang.constants import COLLISION_TYPE_PLAYER
2
3
4def get_editable_puzzlers():
5    classes = []
6    for cls_name, cls in globals().iteritems():
7        if isinstance(cls, type) and hasattr(cls, 'requires'):
8            classes.append((cls_name, cls))
9    return classes
10
11
12class PuzzleGlue(object):
13    """Glue that holds bits of a puzzle together.
14    """
15    def __init__(self):
16        self._components = {}
17
18    def add_component(self, name, puzzler):
19        if not isinstance(puzzler, Puzzler):
20            puzzler = puzzler.puzzler
21            if puzzler is None:
22                # We've got a name, but no puzzler,
23                # so we shouldn't actually be stuck
24                # in here
25                return
26        self._components[name] = puzzler
27        puzzler.set_glue(self)
28
29    def get_state_of(self, name):
30        return self._components[name].get_state()
31
32
33class Puzzler(object):
34    """Behaviour specific to a puzzle component.
35    """
36    def set_glue(self, glue):
37        self.glue = glue
38
39    def set_game_object(self, game_object):
40        self.game_object = game_object
41
42    def get_state(self):
43        raise NotImplementedError()
44
45    @classmethod
46    def requires(cls):
47        """Tell the level editor the arguments we require
48
49           Format is a list of name: type hint tuples"""
50        return [("name", "string")]
51
52
53class YesPuzzler(Puzzler):
54    """Yes sir, I'm always on.
55    """
56    def get_state(self):
57        return True
58
59
60class NoPuzzler(Puzzler):
61    """No sir, I'm always off.
62    """
63    def get_state(self):
64        return False
65
66
67class CollidePuzzler(Puzzler):
68    def __init__(self, *collision_types):
69        if not collision_types:
70            collision_types = (COLLISION_TYPE_PLAYER,)
71        self._collision_types = collision_types
72
73    def get_state(self):
74        space = self.game_object.get_space()
75        for shape in space.shape_query(self.game_object.get_shape()):
76            if shape.collision_type in self._collision_types:
77                return True
78        return False
79
80    @classmethod
81    def requires(cls):
82        return [("name", "string"), ("collision_types", "list of ints")]
83
84
85class ParentAttrPuzzler(Puzzler):
86    def __init__(self, attr_name):
87        self._attr_name = attr_name
88
89    def get_state(self):
90        return getattr(self.game_object, self._attr_name)
91
92    @classmethod
93    def requires(cls):
94        return [("name", "string"), ("attr_name", "string")]
95
96
97class StateProxyPuzzler(Puzzler):
98    def __init__(self, state_source):
99        self._state_source = state_source
100
101    def get_state(self):
102        return self.glue.get_state_of(self._state_source)
103
104    @classmethod
105    def requires(cls):
106        return [("name", "string"), ("sources", "list of names")]
107
108
109class StateLogicalAndPuzzler(Puzzler):
110    def __init__(self, *state_sources):
111        self._state_sources = state_sources
112
113    def get_state(self):
114        for state_source in self._state_sources:
115            if not self.glue.get_state_of(state_source):
116                return False
117        return True
118
119    @classmethod
120    def requires(cls):
121        return [("name", "string"), ("sources", "list of names")]
Note: See TracBrowser for help on using the repository browser.