/
rpg3.py
405 lines (334 loc) · 13.7 KB
/
rpg3.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
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
#!/usr/bin/env python
"""rog3.py class for the game
:author: Jose Carlos Recuero
:version: 0.1
:since: 10/01/2014
"""
__docformat__ = 'restructuredtext en'
###############################################################################
## _ _
## (_)_ __ ___ _ __ ___ _ __| |_ ___
## | | '_ ` _ \| '_ \ / _ \| '__| __/ __|
## | | | | | | | |_) | (_) | | | |_\__ \
## |_|_| |_| |_| .__/ \___/|_| \__|___/
## |_|
###############################################################################
#
# import std python modules
#
import cocos
from cocos.actions import Delay, CallFunc
from cocos.menu import Menu, MenuItem, fixedPositionMenuLayout
from cocos.menu import shake, shake_back
import pyglet
import random
#
# import user python modules
#
import loggerator
import tablecell
import tableboard
import engine
from pieces.axe import Axe
from pieces.bow import Bow
from pieces.coin import Coin
from pieces.dagger import Dagger
from pieces.heart import Heart
from pieces.lance import Lance
from pieces.mana import Mana
from pieces.shield import Shield
from pieces.step import Step
from pieces.staff import Staff
from pieces.sword import Sword
from players.user import User
#import stats
# These assert are to avoid PEP8 complains.
assert Axe
assert Bow
assert Coin
assert Dagger
assert Heart
assert Lance
assert Mana
assert Shield
assert Step
assert Staff
assert Sword
###############################################################################
##
## ___ ___ _ __ ___| |_ __ _ _ __ | |_ ___
## / __/ _ \| '_ \/ __| __/ _` | '_ \| __/ __|
## | (_| (_) | | | \__ \ || (_| | | | | |_\__ \
## \___\___/|_| |_|___/\__\__,_|_| |_|\__|___/
##
###############################################################################
#
###############################################################################
## _ _ _
## ___ _ _| |__ _ __ ___ _ _| |_(_)_ __ ___ ___
## / __| | | | '_ \| '__/ _ \| | | | __| | '_ \ / _ \/ __|
## \__ \ |_| | |_) | | | (_) | |_| | |_| | | | | __/\__ \
## |___/\__,_|_.__/|_| \___/ \__,_|\__|_|_| |_|\___||___/
##
###############################################################################
#
###############################################################################
## _ _ __ _ _ _ _
## ___| | __ _ ___ ___ __| | ___ / _(_)_ __ (_) |_(_) ___ _ __ ___
## / __| |/ _` / __/ __| / _` |/ _ \ |_| | '_ \| | __| |/ _ \| '_ \/ __|
## | (__| | (_| \__ \__ \ | (_| | __/ _| | | | | | |_| | (_) | | | \__ \
## \___|_|\__,_|___/___/ \__,_|\___|_| |_|_| |_|_|\__|_|\___/|_| |_|___/
##
###############################################################################
#
#
#------------------------------------------------------------------------------
class SkillMenu(Menu):
"""
"""
def __init__(self):
"""
"""
super(SkillMenu, self).__init__('Skills')
# Change font size for different menu items.
self.font_title['font_size'] = 16
self.font_item['font_size'] = 8
self.font_item_selected['font_size'] = 10
items = [(MenuItem('Axe', self.on_quit)), (MenuItem('Bow', self.on_quit)), ]
self.create_menu(items,
selected_effect=shake(),
unselected_effect=shake_back(),
layout_strategy=fixedPositionMenuLayout([(250, 460), (250, 430)], ))
def on_quit(self):
exit()
#
#------------------------------------------------------------------------------
class Rpg3(cocos.layer.Layer):
"""
"""
is_event_handler = True
#--------------------------------------------------------------------------
def __init__(self):
""" Initializes Rpg3 instance.
Creates a valid table board and all required widgets and resources for
the game.
"""
super(Rpg3, self).__init__()
self.size = 8
self.user = User('USERNAME')
self.createTableBoard(self.size)
self.logger = loggerator.getLoggerator('rpg3')
self.statsDict = tablecell.TableCell.createAttrsDict()
labelAttrs = {'font_name': 'Times New Roman',
'font_size': 12,
'anchor_x': 'left',
'anchor_y': 'top', }
x, y = 32, 460
self.createCommandLine()
for stat, value in self.user.stats.getStatsData().iteritems():
label = cocos.text.Label('%s: %s' % (stat, value['count']), **labelAttrs)
label.position = x, y
self.add(label, name=stat)
x, y = x, y - 16
self.engine = engine.Engine(self.tableboard, None, self, self.user)
self.add(SkillMenu())
#--------------------------------------------------------------------------
def createCommandLine(self):
""" Create command line widget
Command line widget is used to provide some information to the user
playing the game.
"""
self.cmd = cocos.text.Label('Command Line', position=(400, 460), width=200, height=200, multiline=True)
self.add(self.cmd, name='CommandLine')
self.cmd.line = 0
#--------------------------------------------------------------------------
def newEntryInCommandLine(self, theNewLine):
""" Add a new line to the command line
:type theNewLine: str
:param theNewLine: line to be added to the command line
"""
self.cmd.element.text = '%s\n%s' % (self.cmd.element.text, theNewLine)
#--------------------------------------------------------------------------
def createCellCb(self, thePosition):
""" Callback called when new cell is created
This callback method is passed to the tableboard instance, so when a
new cell has to be created in the tableboard, this will be called.
:type thePosition: tuple
:param thePosition: tuple with the new cell position
:rtype: Cell
:return: Cell instance created
"""
cellStr = random.sample(self.user.stats.getStatsData().keys(), 1)[0]
cellKlass = eval(cellStr.capitalize())
newCell = cellKlass(thePosition)
self.addSprite(newCell.getSprite())
return newCell
#--------------------------------------------------------------------------
def cleanSpritesFromBoard(self):
""" Remove all sprites from the tableboard.
"""
for aSprite in [x for x in self.tableSprites]:
self.removeSprite(aSprite)
#--------------------------------------------------------------------------
def createTableBoard(self, theSize):
""" Create a new table board
It creates a valid tableboard, where there is not any match placed, but
there is at least one possible match to be done in the next movement.
:type theSize: int
:param theSize: table board size x size
:rtype: TableBoard
:return: TableBoard instance created
"""
while True:
self.createBoardPhase = True
self.tableSprites = []
self.tableboard = tableboard.TableBoard(theSize, theNewCellCb=self.createCellCb)
matches = self.tableboard.matchBoard()
# When there is not any match in the board, but there are possible
# match, stop and start the game.
if not self.tableboard.isThereAnyMatch(matches) and self.tableboard.searchForAnyPossibleMatch():
break
self.createBoardPhase = False
for aSprite in self.tableSprites:
self.add(aSprite)
#--------------------------------------------------------------------------
def cellSelected(self):
""" Return a list with all cell selected by the user.
:rtype: list
:return: list with all cell selected
"""
return [aCell for aCell in self.tableboard.iterCell() if aCell.isSelected()]
#--------------------------------------------------------------------------
def processCellSelected(self, x, y):
""" Process cell selected at x, y
Select a cell, when the selected cell is the second one, it proceeds to
swap cells if the are placed together vertically or horizontally.
When the second cell is selected, no matter what at the end no cell is
set to selected in the tableboard.
:type x: int
:param x: cell x position
:type y: int
:param y: cell y position
"""
for aCell in self.tableboard.iterCell():
aCell.select(x, y)
cells = self.cellSelected()
if len(cells) == 2:
if self.tableboard.cellTogetherCell(*cells):
self.tableboard.swapCells(*cells)
[aCell.select() for aCell in cells]
#--------------------------------------------------------------------------
def addSprite(self, theSprite):
""" Add sprite to the scene and any other resource.
:type theSprite: Sprite
:param theSprite: sprite to add
"""
self.tableSprites.append(theSprite)
if not self.createBoardPhase:
self.add(theSprite)
#--------------------------------------------------------------------------
def removeSprite(self, theSprite):
""" Remove sprite from the scene and any other resource.
:type theSprite: Sprite
:param theSprite: sprite to remove
"""
self.remove(theSprite)
self.tableSprites.remove(theSprite)
#--------------------------------------------------------------------------
def replaceSriteForExplosionAtCell(self, theCell):
""" Replace sprite for explosion sprite at the given cell.
:type theCell: tablecell.TableCell
:param theCell: table cell where sprite will be replaced
"""
sprite = cocos.sprite.Sprite('images/explosion.png')
sprite.position = theCell.getSprite().position
self.removeSprite(theCell.getSprite())
theCell.setSprite(sprite)
self.addSprite(theCell.getSprite())
#--------------------------------------------------------------------------
def resetTableboard(self):
""" Reset tableboard with a new one.
Clean all sprites from the tableboard and create a new valid one.
"""
self.cleanSpritesFromBoard()
self.createTableBoard(self.size)
self.newEntryInCommandLine('Reseted Tableboard')
#--------------------------------------------------------------------------
def updateStats(self):
""" Update user stats values with given matches using dungeon engine.
Call tableboard instance to process all matches in the board, then it
process those results and update all required widgets.
"""
userStats = self.user.stats.getStatsData()
for stat, value in userStats.iteritems():
label = self.get(stat)
label.element.text = '%s: %s' % (stat, value['count'])
#--------------------------------------------------------------------------
def replaceSpriteForExplosion(self):
""" Replace all empty cell sprites for explosion sprites.
"""
for aCell in self.tableboard.emptyCellsInBoard():
self.replaceSriteForExplosionAtCell(aCell)
#--------------------------------------------------------------------------
def processMatch(self):
""" Process match using dungeon engine.
"""
matches = self.engine.runMatchPhase()
if matches is not None:
self.updateStats()
self.replaceSpriteForExplosion()
self.scheduleEventAt(0.5, self.updateTableboard)
return True
else:
if not self.tableboard.searchForAnyPossibleMatch():
self.scheduleEventAt(0.5, self.resetTableboard)
return False
#--------------------------------------------------------------------------
def updateTableboard(self):
""" Update table board using dungeon engine.
"""
self.engine.runUpdateTableboard()
for aCell in self.tableboard.emptyCellsInBoard():
self.tableboard.removeCell(aCell.getPosition())
self.removeSprite(aCell.getSprite())
self.tableboard.addNewCell(aCell.getPosition())
self.scheduleEventAt(0, self.processMatch)
#--------------------------------------------------------------------------
def scheduleEventAt(self, theDelay, theAction):
""" Schedule for running theAction at the given theDelay time.
:type theDelay: float
:param theDelay: delay the action should run
:type theAction: func
:param theAction: method to run
"""
self.do(Delay(theDelay) + CallFunc(theAction))
#--------------------------------------------------------------------------
def on_mouse_press(self, x, y, buttons, modifiers):
""" Handle when mouse button is being pressed
:type x: int
:param x: mouse x position
:type y: int
:param y: mouse y position
:type buttons: int
:param buttons: button being pressed
:type modifiers: int
:param modifiers: modifiers
"""
self.processCellSelected(x, y)
self.scheduleEventAt(0, self.processMatch)
###############################################################################
## _
## _ __ ___ __ _(_)_ __
## | '_ ` _ \ / _` | | '_ \
## | | | | | | (_| | | | | |
## |_| |_| |_|\__,_|_|_| |_|
##
###############################################################################
#
if __name__ == '__main__':
pyglet.resource.path.append('images')
pyglet.resource.reindex()
cocos.director.director.init(width=800)
rpg3Layer = Rpg3()
mainScene = cocos.scene.Scene(rpg3Layer)
cocos.director.director.run(mainScene)