-
Notifications
You must be signed in to change notification settings - Fork 0
/
blocks.py
334 lines (291 loc) · 10.9 KB
/
blocks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
import os
import logging
logger=logging.getLogger('programmer')
import pygame
from pygame.locals import *
import lib
import input
class block(object):
#non interface stuff
def __init__(self,img,lable=None,num=None):
'''example init:::
block(os.path.join(~~~~~),pygame.font.render(~~~~~),1)
we draw img's onto fake smaller surface so that we can use IT for an absilute topleft'''
##TODO::: make "active" setting for textbox, and other settings???
if type(img) in (str,tuple,list):
if type(img) in (tuple,list):
##list of directories to join are passed along...
self.img = lib.common.load_img(*img)
else:
##string name (already passed through os.path.join?)
self.img = lib.common.load_img(img)
else:
self.img=img
self.lable = lable
if lable:
self.lable_pos = lable.get_rect()
self.lable_pos.midtop = 39,10
self.surf = pygame.Surface((80,80),pygame.SRCALPHA)
self.drag_rect=pygame.Rect((0,0),(10,10))
if num is not None:
if isinstance(num,input.Input):
self.tbox = num
else:
self.tbox = input.Input(y=40,x=40,maxlength=3, color=(255,0,0), prompt='#:', restricted='0123456789')
self._old_tbox_value = ''
else:
#used to let us know NOT to try and render this section
self.tbox = None
self.active = False
#nothing can link by default to a default block, use a subclass!
self.link_down = False
self.link_up = False
self.link_left = False
self.link_right = False
#block-linkers:
self._dblock=None
self._ublock=None
self._rblock=None
self._lblock=None
#can this block be dragged? (override in sub classes!)
self.draggable = False
self.color = (255,255,0)#outline color
def draw(self,screen,rect):
self.surf.blit(self.img,(0,0))
if self.lable:
self.surf.blit(self.lable,self.lable_pos)
if self.tbox:
self.tbox.draw(self.surf,self.active)
screen.blit(self.surf,rect)
def event_engine(self,events,pmap,loc):
'''run by every tile in the grid,so dont take TOO long.
notes:::
1: use self.active for events that should only happen when a tile is currently selected as "active" eg: text_box update
2: if sub classes wish to over-ride this, fine, just call it to do background stuff. (unless you want a block to ignore you)
'''
if self.tbox and self.active:
self.tbox.update(events,True)
if self._old_tbox_value != self.tbox.value:
self._old_tbox_value = self.tbox.value
pmap.render()
for event in events:
if event.type == KEYDOWN:
if event.key == K_RETURN:
pass
elif event.type == MOUSEBUTTONDOWN and event.button==1:
if self.tbox:
if self.tbox.rect.collidepoint(self._rel_click(pmap,event.pos)):
self.active = True
else:
self.active = False
##link block decorators:::
##if "set", tey set themselves to other, and also set other.xblock to self(or none if unlinking)
@lib.decorators.propget
def dblock(self):
return self._dblock
@lib.decorators.propset
def dblock(self,other):
if other is None:
#set the other block's corrisponing to None as well...
#use name in self because other is None right now...
try:
self._dblock._ublock = None
except AttributeError as e:
pass
else:
other._ublock = self
self._dblock = other
@lib.decorators.propget
def ublock(self):
return self._ublock
@lib.decorators.propset
def ublock(self,other):
if other is None:
#set the other block's corrisponing to None as well...
try:
self._ublock._dblock = None
except AttributeError as e:
pass
else:
other._dblock = self
self._ublock = other
@lib.decorators.propget
def lblock(self):
return self._lblock
@lib.decorators.propset
def lblock(self,other):
if other is None:
#set the other block's corrisponing to None as well...
try:
self._lblock._rblock = None
except AttributeError as e:
pass
else:
other._rblock = self
self._lblock = other
@lib.decorators.propget
def rblock(self):
return self._rblock
@lib.decorators.propset
def rblock(self,other):
if other is None:
#set the other block's corrisponing to None as well...
try:
self._rblock._lblock = None
except AttributeError as e:
pass
else:
other._lblock = self
self._rblock = other
##location properties
@lib.decorators.propget
def loc(self):
return self.__loc
@lib.decorators.propset
def loc(self,value):
self.__loc = value
#action stuff
def action(self,robot):
'''robotic action to take (turn, go fwd, scan/make desision)'''
pass
def next(self,robot):
'''what is the next block? (give (x,y) or instance?)'''
pass
def check_drag_click(self,pmap,mouse_pos,map_pos):
'''see if click registers on this tiles self.click_rect'''
return self.drag_rect.collidepoint(self._rel_click(pmap,mouse_pos,map_pos))
def _rel_click(self,pmap,mouse_pos,map_pos=None):
if map_pos is None:
map_pos = pmap.click_engine(mouse_pos)
if map_pos == self.loc:
return (mouse_pos[0]%pmap.sub_rect.width,mouse_pos[1]%pmap.sub_rect.height)
else:
return (-1,-1)
def drag(self,pmap):
'''cleans up object for a 'drop' '''
self.dblock = None
self.ublock = None
self.lblock = None
self.rblock = None
pmap.map[self.loc][0] = bgnd_block()
return self
def able_drop(self,pos,pmap):
'''find any problems with the drop and return False if obstructed.
else return True'''
pass
def drop(self,pos,pmap):
'''finalize a drop. actually places block on grid'''
pass
def __getstate__(self):
state=self.__dict__.copy()
state.pop('lable')
state.pop('surf')
state.pop('img')
#if not isinstance(self,bgnd_block):
# print self,self.dblock
return state
def __setstate__(self,state):
self.__dict__.update(state)
if hasattr(self,'text'):
self.lable=lib.common.font.render(*self.text).convert_alpha()
else:
self.lable = None
self.img=lib.common.load_img(*self.file)
self.surf = pygame.Surface((80,80),pygame.SRCALPHA)
#if not isinstance(self,bgnd_block):
# print self,self.dblock
class bgnd_block(block):
def __init__(self):
self.file=('gui','programmer','background_bgnd.png')
block.__init__(self,self.file)
self.link_down = False
self.link_up = True
self.blank = True
self.loc = (0,0)
def event_engine(self,events,pmap,loc):
'''we are a blank block, dont care none about them events'''
pass
class vertical_block(block):
def __init__(self,img,lable=None,num=None):
block.__init__(self,img,lable,num)
self.link_up = True
self.link_down = True
self.draggable = True
def next(self,robot):
if self.dblock:
return self.dblock
else:
return False
def able_drop(self,pos,pmap):
#firstly: check for up block
up=pos[0],pos[1]-1
if up[1] < 0:
logger.debug('we are at the top, cant place block here!')
return False
if not pmap.map[up][0].link_down:
logger.debug('block above cant be linked downwards, cant place block there!')
return False
#secondly: check for down block:
down=pos[0],pos[1]+1
#we dont care about running off the map if down is off, because this block is able to "end" code
#but lets check IF there even IS a block there...
if pmap.map.has_key(down):
if not pmap.map[down][0].link_up:
logger.debug('block below doesnt allow linking')
return False
return True
def drop(self,pos,pmap):
if self.able_drop(pos,pmap):
pmap.map[pos][0]=self
up=pos[0],pos[1]-1
pmap.map[up][0].dblock = self
down=pos[0],pos[1]+1
pmap.map[down][0].ublock = self
else:
raise Error('must be able to place block before drop')
self.loc=pos
class pfwd_block(vertical_block):
def __init__(self):
self.file=('gui','programmer','blank_vert.png')
img=lib.common.load_img(*self.file)
self.text=('Forward',True,(255,0,0))
lable = lib.common.font.render(*self.text).convert_alpha()
num=True
vertical_block.__init__(self,img,lable,num)
def action(self,robot):
try:times=int(self.tbox.value)
except:times=1
for i in range(times):
robot.move_fwd()
class trnl_block(vertical_block):
def __init__(self):
self.file = ('gui','programmer','blank_vert.png')
img=lib.common.load_img(*self.file)
self.text=('Turn Left',True,(255,0,0))
lable = lib.common.font.render(*self.text).convert_alpha()
vertical_block.__init__(self,img,lable)
def action(self,robot):
robot.turn('left')
class trnr_block(vertical_block):
def __init__(self):
self.file = ('gui','programmer','blank_vert.png')
img=lib.common.load_img(*self.file)
self.text=('Turn Right',True,(255,0,0))
lable = lib.common.font.render(*self.text).convert_alpha()
vertical_block.__init__(self,img,lable)
def action(self,robot):
robot.turn('right')
class main_block(block):
def __init__(self,loc):
self.file=('gui','programmer','main_main.png')
block.__init__(self,self.file)
self.link_down=True
self.loc=loc
def action(self,robot):
'''do nothing, pass along. this is not the robot you are looking for'''
pass
def next(self,robot):
if self.dblock:
return self.dblock
else:
return False