^(9-TSI;f9E
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℘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
Fe*lCUF$4er
literal 0
HcmV?d00001
diff --git a/corelib.py b/corelib.py
new file mode 100644
index 0000000..3453c62
--- /dev/null
+++ b/corelib.py
@@ -0,0 +1,168 @@
+import os, sys, json
+
+import threading, Gamecore.guiDrawWaiting
+from PyQt5 import QtCore, QtGui, QtWidgets
+from PyQt5.QtWidgets import *
+from PyQt5.Qt import *
+
+with open('Gamecore/config.json', 'r', encoding='utf-8') as cfg:
+ cfg = json.loads(cfg.read())
+
+if cfg["pythonRun"]:
+ if sys.platform == 'win32':
+ runCoreApp = cfg["pythonPath_win32"]
+ else:
+ runCoreApp = cfg["pythonPath_unix"]
+else:
+ if sys.platform == 'win32':
+ runCoreApp = 'start '
+ else:
+ runCoreApp = './'
+
+
+class tool:
+ def __init__(self):
+ def showGUI():
+ class coreGUI(threading.Thread):
+ def run(self):
+ class app_win(QMainWindow):
+ def __init__(self):
+ super(app_win, self).__init__()
+ self.ui = Gamecore.guiDrawWaiting.Ui_Form()
+ self.ui.setupUi(self)
+ self.show()
+
+ self.app = QApplication([])
+ self.application = app_win()
+ self.app.exec()
+
+ def stop(self):
+ self.application.hide()
+ del self
+
+ thrObj = coreGUI()
+ thrObj.start()
+ return thrObj
+
+ def noneGUI(*args, **kwargs):
+ pass
+
+ def stopGUI(thrObj):
+ thrObj.stop()
+
+ self.showGUI = showGUI
+ self.noneGUI = noneGUI
+ self.stopGUI = stopGUI
+
+ self.wait = self.noneGUI
+ self.resp = self.noneGUI
+
+ def showGUI_wait(self, show=True):
+ if show:
+ print('WARNING! You will be using GUI corelib!!!')
+ self.wait = self.showGUI
+ self.resp = self.stopGUI
+ else:
+ self.wait = self.noneGUI
+ self.resp = self.noneGUI
+
+ def response(self, resp):
+ waitObj = self.wait()
+
+ respf = open('Gamecore/gamestat.json', 'wt', encoding='utf-8')
+ respf.write(json.dumps(resp, indent="\t", ensure_ascii=False))
+ respf.close()
+
+ shellScript = open('runCore.sh', 'wt', encoding='utf-8')
+ print(f"cd Gamecore\n{runCoreApp}{cfg['core_file']}")
+ shellScript.write(f"cd Gamecore\n{runCoreApp}{cfg['core_file']}")
+ shellScript.close()
+ if sys.platform != 'win32':
+ os.system("./runCore.sh")
+ else:
+ os.system("runCore.sh")
+
+ output = open('Gamecore/response.json', 'r', encoding='utf-8')
+ outp = output.read()
+ output.close()
+
+ returnObj = json.loads(outp)
+ self.resp(waitObj)
+ return returnObj
+
+
+tool = tool()
+
+
+def newGame(ID, mines=25, fieldsize=10):
+ return tool.response({
+ "status": "newGame",
+ "request": {
+ "ID": ID,
+ "Mines": mines,
+ "size": fieldsize
+ }
+ })
+
+
+def openItem(gamesession, X, Y):
+ return tool.response({
+ "status": "openItem",
+ "request": {
+ "gamesession": gamesession,
+ "X": X,
+ "Y": Y
+ }
+ })
+
+
+def getGameSession(gamesession):
+ return tool.response({
+ "status": "getGameSession",
+ "request": {
+ "gamesession": gamesession
+ }
+ })
+
+
+def toggleFlag(gamesession, X, Y):
+ return tool.response({
+ "status": "toggleFlag",
+ "request": {
+ "gamesession": gamesession,
+ "X": X,
+ "Y": Y
+ }
+ })
+
+
+class Method:
+ def __init__(self, method, **kwargs):
+ self.method = method
+ self.kwargs = kwargs
+
+ def start(self):
+ return eval(self.method)(**kwargs)
+
+
+class multiMethod:
+ def __init__(self, *methods):
+ self.methods = list(methods)
+
+ def append(self, method):
+ self.methods.append(method)
+
+ def pop(self, index):
+ self.methods.pop(index)
+
+ def __len__(self):
+ return len(self.methods)
+
+ def start(self):
+ request = {"status": 'multiMethod', 'requests': list()}
+ for method in self.methods:
+ request['requests'].append({
+ "status": method.method,
+ "request": method.kwargs
+ })
+ return tool.response(request)
\ No newline at end of file
diff --git a/game.py b/game.py
new file mode 100644
index 0000000..3af9e11
--- /dev/null
+++ b/game.py
@@ -0,0 +1,951 @@
+from PyQt5 import QtCore, QtGui, QtWidgets
+from PyQt5.QtWidgets import *
+from PyQt5.Qt import *
+import SQLEasy, json, os, random, corelib
+import launcher # Интерфейс
+
+
+def game(gameStyle, databaseObj, gamerID, gamehash, muzicOn=True, MINES=random.randint(25, 55)):
+ MINES_COMPR = False
+ import pygame
+
+ corelib.tool.showGUI_wait()
+
+ databaseObj.setItem('lastGame', gameStyle, 'ID', gamerID, DatabaseName='users')
+ # Импорт конфига
+ with open(f"source/{gameStyle}/about.json", 'r', encoding='utf-8') as gameconfig:
+ gameconfig = json.loads(gameconfig.read())
+ # Функции
+
+
+ def checkEnd(field):
+ endgame = True
+ for r in field:
+ for c in r:
+ if c in ('M:O', 'M', 'M:F'):
+ return True
+ if 'R' in c and ':O' not in c:
+ endgame = False
+ return endgame
+
+
+ def checkWin(field, endgamecheck=False):
+ fieldCheck = list()
+ endgame = True
+ for r in field:
+ for c in r:
+ fieldCheck.append(c)
+ if 'R' in c and ':O' not in c:
+ endgame = False
+ if endgamecheck:
+ return 'M:O' not in fieldCheck and endgame
+ else:
+ return 'M:O' not in fieldCheck
+
+
+ def compareFields(old_field, field):
+ if checkWin(field, True):
+ return
+
+ class emptySound:
+ def play(self):
+ pass
+
+ sounds = [
+ emptySound(),
+ pygame.mixer.Sound(f"source/{gameStyle}/openCell.wav"),
+ pygame.mixer.Sound(f"source/{gameStyle}/flag.wav")
+ ]
+
+ actID = 0
+
+ comlete = False
+
+ for rowID in range(len(field)):
+ for cellID in range(len(field[rowID])):
+ if field[rowID][cellID] != old_field[rowID][cellID]:
+ if ':F' in field[rowID][cellID]:
+ actID = 2
+ comlete = True
+ break
+ elif ':O' in field[rowID][cellID] and field[rowID][cellID] != 'M:O':
+ actID = 1
+ comlete = True
+ break
+ if comlete:
+ break
+
+ sounds[actID].play()
+ # Классы игровых объектов
+
+
+ class controlBanner(pygame.sprite.Sprite):
+ def __init__(self, X, Y, platform='XBox', info_contentID=0):
+ infocontent = ['openCell', 'flagCell', 'restart']
+ pygame.sprite.Sprite.__init__(self)
+ self.image = pygame.Surface((228, 77))
+ self.platform = platform
+ self.info_contentID = info_contentID
+ self.image = pygame.image.load(f"source/{gameStyle}/{platform}_{infocontent[info_contentID]}.png")
+ self.rect = self.image.get_rect()
+ self.rect.x = X
+ self.rect.y = Y
+
+ def changePlatform(self, platform):
+ infocontent = ['openCell', 'flagCell', 'restart']
+ self.platform = platform
+ self.image = pygame.image.load(f"source/{gameStyle}/{platform}_{infocontent[self.info_contentID]}.png")
+
+
+ class Border(pygame.sprite.Sprite):
+ def __init__(self, X, Y, borderType='Left'):
+ pygame.sprite.Sprite.__init__(self)
+ self.image = pygame.Surface((228, 77))
+ self.animationFrameTime = 0
+ self.borderType = borderType
+ self.image = pygame.image.load(f"source/{gameStyle}/score_end{borderType}(0).png")
+ self.rect = self.image.get_rect()
+ self.rect.x = X
+ self.rect.y = Y
+
+ def update(self):
+ self.animationFrameTime += 1
+ if self.animationFrameTime >= 45:
+ self.animationFrameTime = 0
+ self.image = pygame.image.load(f"source/{gameStyle}/score_end{self.borderType}({self.animationFrameTime // 15}).png")
+
+
+ class resetButton(pygame.sprite.Sprite):
+ def __init__(self, X, Y):
+ pygame.sprite.Sprite.__init__(self)
+ self.image = pygame.Surface((228, 77))
+ self.hide = 'noHover'
+ self.endStatus = ''
+ self.image = pygame.image.load(f"source/{gameStyle}/resetButton_{self.endStatus}_{self.hide}.png")
+ self.rect = self.image.get_rect()
+ self.x = X
+ self.y = Y
+
+ self.rect.x = X
+ self.rect.y = Y
+
+ def editCond(self, hide=None, endStatus=None):
+ if not(hide is None):
+ self.hide = hide
+ if not(endStatus is None):
+ self.endStatus = endStatus
+
+ self.image = pygame.image.load(f"source/{gameStyle}/resetButton_{self.endStatus}_{self.hide}.png")
+
+ def check_myself_Location(self, X, Y):
+ if X >= self.x and X <= self.x + 32 and Y >= self.y and Y <= self.y + 32:
+ return self
+
+
+ class timerCell(pygame.sprite.Sprite):
+ def __init__(self, X, Y, value='off'):
+ pygame.sprite.Sprite.__init__(self)
+ self.image = pygame.Surface((228, 77))
+ self.value = value
+ self.image = pygame.image.load(f"source/{gameStyle}/score_{value}.png")
+ self.rect = self.image.get_rect()
+ self.rect.x = X
+ self.rect.y = Y
+
+ def editValue(self, value='off'):
+ self.value = value
+ self.image = pygame.image.load(f"source/{gameStyle}/score_{self.value}.png")
+
+ def update(self):
+ self.image = pygame.image.load(f"source/{gameStyle}/score_{self.value}.png")
+
+
+ class tablet(pygame.sprite.Sprite):
+ def __init__(self, X, Y):
+ pygame.sprite.Sprite.__init__(self)
+ self.image = pygame.Surface((228, 77))
+ self.image = pygame.image.load(f"source/{gameStyle}/Tablet.png")
+ self.rect = self.image.get_rect()
+ self.rect.x = X
+ self.rect.y = Y
+
+
+ class fieldCursor(pygame.sprite.Sprite):
+ def __init__(self, X, Y):
+ pygame.sprite.Sprite.__init__(self)
+ self.image = pygame.Surface((32, 32))
+ self.image = pygame.image.load(f"source/{gameStyle}/Cursor.png")
+ self.cellPos = (X, Y)
+ self.rect = self.image.get_rect()
+ self.rect.x = 93 + X * 31
+ self.rect.y = 133 + Y * 31
+
+ def setCell_coord(self, X, Y):
+ self.rect.x = 93 + X * 31
+ self.rect.y = 133 + Y * 31
+ self.cellPos = (X, Y)
+
+
+ class cell(pygame.sprite.Sprite):
+ def __init__(self, X, Y, coords, condition='CLOSED'):
+ pygame.sprite.Sprite.__init__(self)
+ self.image = pygame.Surface((32, 32))
+ self.image = pygame.image.load(f"source/{gameStyle}/closed_cell.png")
+ self.rect = self.image.get_rect()
+ self.rect.x = X
+ self.rect.y = Y
+ self.cellPosition = {
+ "X": coords[0],
+ "Y": coords[1]
+ }
+
+ self.condition = condition
+ self.animationFrameS = 0
+
+ def getCondition(self):
+ return self.condition
+
+ def update(self):
+ if self.condition == 'CLOSED':
+ self.image.blit(pygame.image.load(f"source/{gameStyle}/closed_cell.png"), (0, 0))
+ elif 'num_' in self.condition:
+ number = int(self.condition.split('_')[-1])
+ self.animationFrameS += 1
+ if self.animationFrameS >= 40:
+ self.animationFrameS = 0
+ self.image.blit(pygame.image.load(f"source/{gameStyle}/mines_{number}({self.animationFrameS // 20}).png"), (0, 0))
+ elif self.condition == 'OPENED':
+ self.animationFrameS += 1
+ if self.animationFrameS >= 40:
+ self.animationFrameS = 0
+ self.image.blit(pygame.image.load(f"source/{gameStyle}/open_cell_{self.animationFrameS // 20}.png"), (0, 0))
+ elif self.condition == 'FLAG':
+ self.animationFrameS += 1
+ if self.animationFrameS >= 40:
+ self.animationFrameS = 0
+ self.image.blit(pygame.image.load(f"source/{gameStyle}/flag_{self.animationFrameS // 20}.png"), (0, 0))
+ elif self.condition == 'BOMB':
+ self.animationFrameS += 1
+ if self.animationFrameS >= 40:
+ self.animationFrameS = 0
+ self.image.blit(pygame.image.load(f"source/{gameStyle}/mine_bombed({self.animationFrameS // 20}).png"), (0, 0))
+ elif self.condition == 'DEFUSE':
+ self.animationFrameS += 1
+ if self.animationFrameS >= 40:
+ self.animationFrameS = 0
+ self.image.blit(pygame.image.load(f"source/{gameStyle}/mine_finded({self.animationFrameS // 20}).png"), (0, 0))
+
+ def setCondition(self, value):
+ self.condition = value
+
+
+ class sceneGame(pygame.sprite.Group):
+ def __init__(self, platform):
+ pygame.sprite.Group.__init__(self)
+ # Sounds
+ self.bombSound = pygame.mixer.Sound(f"source/{gameStyle}/bomb.wav")
+ self.winSound = pygame.mixer.Sound(f"source/{gameStyle}/win.wav")
+
+ self.soundNotPlayed = True
+
+ self.PLATFORM = platform
+ self.cells = list()
+ for row in range(10):
+ self.cells.append(list())
+ for _cell in range(10):
+ addCell = cell(93 + _cell * 31, 133 + row * 31, (_cell, row))
+ self.add(addCell)
+ self.cells[-1].append({
+ "cellObject": addCell,
+ "coord_start": [93 + _cell * 31, 133 + row * 31],
+ "coord_last": [93 + (_cell + 1) * 31, 133 + (row + 1) * 31],
+ "coords_in_field": (_cell, row)
+ })
+ self.add(tablet(130, 14))
+ self.positionCursor = (0, 0)
+ self.cursor = fieldCursor(*self.positionCursor)
+ self.add(self.cursor)
+ self.add(Border(166, 93))
+ self.timeCells = list()
+ for i in range(3):
+ timerCellObj = timerCell(198 + i * 32, 93)
+ self.add(timerCellObj)
+ self.timeCells.append(timerCellObj)
+ self.add(Border(294, 93, 'Right'))
+ self.resetButton = resetButton(228, 448)
+ self.add(self.resetButton)
+
+ self.InfoTables = list()
+
+ for i in range(3):
+ control_banner = controlBanner(0, 404 + i * 32, platform, i)
+ self.add(control_banner)
+ self.InfoTables.append(control_banner)
+
+ def changePlatform(self, PLATFORM):
+ self.PLATFORM = PLATFORM
+ for tableObj in self.InfoTables:
+ tableObj.changePlatform(PLATFORM)
+
+ def setScoreBoard_value(self, value=None):
+ if not(value is None):
+ value = str(value)
+ if len(value) == 1:
+ value = '00' + value
+ elif len(value) == 2:
+ value = '0' + value
+
+ for numID in range(len(value)):
+ self.timeCells[numID].editValue(int(value[numID]))
+ else:
+ for cellT in self.timeCells:
+ cellT.editValue()
+
+ def getCell_intoCoords(self, x, y):
+ for row in self.cells:
+ for _cell in row:
+ if (x >= _cell["coord_start"][0] and x <= _cell["coord_last"][0]) and (y >= _cell["coord_start"][1] and y <= _cell["coord_last"][1]):
+ return _cell["cellObject"]
+
+ def cursorMove(self, x, y):
+ self.positionCursor = (x, y)
+ self.cursor.setCell_coord(x, y)
+
+ def get_cursorPos(self):
+ return list(self.positionCursor)
+
+ def updateField(self, field, gamefinished=None):
+ global MINES_COMPR
+
+ listcells = list()
+ for r in field:
+ for c in r:
+ listcells.append(c)
+ if gamefinished is None:
+ gamefinished = 'M:O' in listcells
+
+ for rowId in range(len(field)):
+ row = field[rowId]
+ for cellID in range(len(field[rowId])):
+ _cell = field[rowId][cellID]
+
+ actCell = self.cells[rowId][cellID]["cellObject"]
+ if ':O' in _cell:
+ if not(gamefinished):
+ gamefinished = _cell == 'M:O'
+
+ if _cell == 'M:O':
+ actCell.setCondition('BOMB')
+ else:
+ SeeUp = rowId != 0
+ SeeDown = rowId != len(field) - 1
+ SeeLeft = cellID != 0
+ SeeRight = cellID != len(field) - 1
+
+ mines = 0
+ frontire = False
+ if SeeUp:
+ if field[rowId - 1][cellID] in ('M', 'M:F', 'M:O'):
+ mines += 1
+ if not(frontire):
+ frontire = _cell != field[rowId - 1][cellID] and ':O' not in field[rowId - 1][cellID]
+ if SeeDown:
+ if field[rowId + 1][cellID] in ('M', 'M:F', 'M:O'):
+ mines += 1
+ if not(frontire):
+ frontire = _cell != field[rowId + 1][cellID] and ':O' not in field[rowId + 1][cellID]
+ if SeeLeft:
+ if field[rowId][cellID - 1] in ('M', 'M:F', 'M:O'):
+ mines += 1
+ if not(frontire):
+ frontire = _cell != field[rowId][cellID - 1] and ':O' not in field[rowId][cellID - 1]
+ if SeeRight:
+ if field[rowId][cellID + 1] in ('M', 'M:F', 'M:O'):
+ mines += 1
+ if not(frontire):
+ frontire = _cell != field[rowId][cellID + 1] and ':O' not in field[rowId][cellID + 1]
+ # Диагонали
+ if SeeUp and SeeLeft:
+ if field[rowId - 1][cellID - 1] in ('M', 'M:F', 'M:O'):
+ mines += 1
+ if SeeUp and SeeRight:
+ if field[rowId - 1][cellID + 1] in ('M', 'M:F', 'M:O'):
+ mines += 1
+ if SeeDown and SeeLeft:
+ if field[rowId + 1][cellID - 1] in ('M', 'M:F', 'M:O'):
+ mines += 1
+ if SeeDown and SeeRight:
+ if field[rowId + 1][cellID + 1] in ('M', 'M:F', 'M:O'):
+ mines += 1
+
+ if mines > 0:
+ actCell.setCondition('num_%s' % mines)
+ elif frontire:
+ actCell.setCondition('num_1')
+ else:
+ actCell.setCondition('OPENED')
+ elif ':F' in _cell:
+ if gamefinished and _cell == 'M:F':
+ actCell.setCondition('DEFUSE')
+ else:
+ actCell.setCondition('FLAG')
+ else:
+ actCell.setCondition('CLOSED')
+ if not(gamefinished):
+ self.resetButton.editCond(endStatus='')
+ elif checkWin(field):
+ MINES_COMPR = True
+ self.resetButton.editCond(endStatus='win')
+ self.winSound.play()
+ minesDefused = 0
+ scores = 0
+
+ for row in field:
+ for _cell in row:
+ if _cell == 'M:F':
+ minesDefused += 1
+
+ for row in field:
+ for _cell in row:
+ if _cell == 'M:F':
+ if (minesDefused // 5) ** 2 > 15:
+ scores += (minesDefused // 5) ** 2 > 10
+ else:
+ scores += 15
+
+ databaseObj.setItem(
+ 'minesDefuse',
+ SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['minesDefuse'] + minesDefused,
+ 'ID',
+ gamerID,
+ DatabaseName='users'
+ )
+
+ databaseObj.setItem(
+ 'points',
+ SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['points'] + scores,
+ 'ID',
+ gamerID,
+ DatabaseName='users'
+ )
+ else:
+ MINES_COMPR = True
+ self.resetButton.editCond(endStatus='lose')
+ self.bombSound.play()
+
+ minesDefused = 0
+ scores = 0
+
+ for row in field:
+ for _cell in row:
+ if _cell == 'M:F':
+ minesDefused += 1
+ scores += 10
+
+ databaseObj.setItem(
+ 'minesDefuse',
+ SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['minesDefuse'] + minesDefused,
+ 'ID',
+ gamerID,
+ DatabaseName='users'
+ )
+
+ databaseObj.setItem(
+ 'points',
+ SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['points'] + scores,
+ 'ID',
+ gamerID,
+ DatabaseName='users'
+ )
+
+
+ # код игры
+ logicGame = corelib.getGameSession(gamehash)['response']
+ gamesession = logicGame["gamesession"]
+ field = logicGame["map"]
+
+ if gamesession not in SQLEasy.compareKey(databaseObj.getBase('gamehashes'), 'hash'):
+ databaseObj.add({
+ "hash": gamesession,
+ "userID": gamerID,
+ "mines": MINES,
+ "game": gameStyle,
+ "fieldJSON": json.dumps(field, indent="\t", ensure_ascii=False)
+ }, 'gamehashes')
+
+ pygame.init()
+
+ screen = pygame.display.set_mode((500, 500))
+
+ pygame.display.set_caption(gameconfig['title'])
+ pygame.display.set_icon(pygame.image.load(f"source/{gameStyle}/gameico.png"))
+ bg = pygame.image.load(f"source/{gameStyle}/bg.png")
+ screen.blit(bg, (0, 0))
+
+ PLATFORM = 'XBox' # (!) Сделать проверку
+ # Прорисовка полей
+ sceneGame = sceneGame(PLATFORM)
+
+ pygame.display.flip()
+
+ program_running = True
+
+ cursor_moveUp = False
+ cursor_moveDown = False
+ cursor_moveLeft = False
+ cursor_moveRight = False
+
+ # Muzic
+ pygame.mixer.music.load(f"source/{gameStyle}/muzic.wav")
+ if muzicOn:
+ pygame.mixer.music.play()
+ pygame.mixer.Sound(f"source/{gameStyle}/resetField.wav").play()
+ databaseObj.setItem(
+ 'games',
+ SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['games'] + 1,
+ 'ID',
+ gamerID,
+ DatabaseName='users'
+ )
+
+ sceneGame.updateField(field)
+
+ while program_running:
+ pygame.time.Clock().tick(60) # max FPS
+ for event in pygame.event.get():
+ if event.type == pygame.QUIT:
+ program_running = False
+ break
+ elif event.type == pygame.MOUSEMOTION:
+ POSITION = event.pos
+ cellSel = sceneGame.getCell_intoCoords(int(POSITION[0]), int(POSITION[1]))
+
+ resetButtonSel = sceneGame.resetButton.check_myself_Location(int(POSITION[0]), int(POSITION[1]))
+ if not(cellSel is None):
+ sceneGame.cursorMove(cellSel.cellPosition["X"], cellSel.cellPosition["Y"])
+ del POSITION, cellSel
+ if not(resetButtonSel is None):
+ resetButtonSel.editCond(hide='hover')
+ else:
+ sceneGame.resetButton.editCond(hide='noHover')
+ elif event.type == pygame.KEYDOWN:
+ cursor_moveUp = event.key == 1073741906
+ cursor_moveDown = event.key == 1073741905
+ cursor_moveLeft = event.key == 1073741904
+ cursor_moveRight = event.key == 1073741903
+
+ cursor_coords = sceneGame.get_cursorPos()
+ if cursor_moveUp:
+ cursor_coords[1] -= 1
+ if cursor_moveDown:
+ cursor_coords[1] += 1
+ if cursor_moveLeft:
+ cursor_coords[0] -= 1
+ if cursor_moveRight:
+ cursor_coords[0] += 1
+
+ if cursor_coords[0] <= -1:
+ cursor_coords[0] = 9
+ if cursor_coords[0] >= 10:
+ cursor_coords[0] = 0
+ if cursor_coords[1] <= -1:
+ cursor_coords[1] = 9
+ if cursor_coords[1] >= 10:
+ cursor_coords[1] = 0
+
+ sceneGame.cursorMove(*cursor_coords)
+ elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
+ POSITION = event.pos
+ cellSel = sceneGame.getCell_intoCoords(int(POSITION[0]), int(POSITION[1]))
+
+ resetButtonSel = sceneGame.resetButton.check_myself_Location(int(POSITION[0]), int(POSITION[1]))
+ if not(cellSel is None):
+ corelib.openItem(gamesession, X=cellSel.cellPosition["X"], Y=cellSel.cellPosition["Y"])
+ respObj = corelib.getGameSession(gamesession)['response']
+ old_field = field
+ field = respObj['map']
+ compareFields(old_field, field)
+ sceneGame.updateField(field, gamefinished=not(respObj['continue']))
+ del POSITION, cellSel
+ if not(resetButtonSel is None):
+ pygame.mixer.Sound(f"source/{gameStyle}/resetField.wav").play()
+ MINES = random.randint(25, 55)
+ logicGame = corelib.newGame(gamerID, mines=MINES)['response']
+ gamesession = logicGame["gamesession"]
+ sceneGame.updateField(logicGame["map"])
+ if muzicOn:
+ pygame.mixer.music.play()
+ MINES_COMPR = False
+
+ databaseObj.setItem(
+ 'games',
+ SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['games'] + 1,
+ 'ID',
+ gamerID,
+ DatabaseName='users')
+
+ databaseObj.add({
+ "hash": gamesession,
+ "userID": gamerID,
+ "game": gameStyle,
+ "mines": MINES,
+ "fieldJSON": json.dumps(field, indent="\t", ensure_ascii=False)
+ }, 'gamehashes')
+ elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 3:
+ POSITION = event.pos
+ cellSel = sceneGame.getCell_intoCoords(int(POSITION[0]), int(POSITION[1]))
+ if not(cellSel is None):
+ if MINES > 0 and cellSel.getCondition() == 'CLOSED' and not(MINES_COMPR):
+ if 'response' in corelib.toggleFlag(gamesession, X=cellSel.cellPosition["X"], Y=cellSel.cellPosition["Y"]):
+ MINES -= 1
+ respObj = corelib.getGameSession(gamesession)['response']
+ old_field = field
+ field = respObj['map']
+ compareFields(old_field, field)
+ sceneGame.updateField(field, gamefinished=not(respObj['continue']))
+ del POSITION, cellSel
+ elif cellSel.getCondition() == 'FLAG' and not(MINES_COMPR):
+ if 'response' in corelib.toggleFlag(gamesession, X=cellSel.cellPosition["X"], Y=cellSel.cellPosition["Y"]):
+ MINES += 1
+ respObj = corelib.getGameSession(gamesession)['response']
+ old_field = field
+ field = respObj['map']
+ compareFields(old_field, field)
+ sceneGame.updateField(field, gamefinished=not(respObj['continue']))
+ del POSITION, cellSel
+ databaseObj.setItem(
+ 'mines',
+ MINES,
+ 'hash',
+ gamesession,
+ DatabaseName='gamehashes'
+ )
+
+ sceneGame.setScoreBoard_value(MINES)
+
+ sceneGame.draw(screen)
+ sceneGame.update()
+ pygame.display.flip()
+
+ pygame.quit()
+
+
+def getGamesDict():
+ listGames = dict()
+ for directory in [f for f in os.listdir('source') if len(f.split('.')) == 1]:
+ if 'about.json' in os.listdir(f"source/{directory}"):
+ f = open(f"source/{directory}/about.json", 'r', encoding='utf-8')
+ content = json.loads(f.read())
+ listGames[directory] = {
+ "gamename": content['title'],
+ "path": f"source/{directory}"
+ }
+ return listGames
+
+
+def getGameName(name):
+ if name in getGamesDict():
+ return getGamesDict()[name]["gamename"]
+ else:
+ return 'Game not founded.'
+
+
+class app_win(QMainWindow):
+ def __init__(self):
+ super(app_win, self).__init__()
+ self.ui = launcher.Ui_Form()
+ self.ui.setupUi(self)
+
+ self.database = SQLEasy.database('gameDataBase.db')
+
+ # Во-первых, наполним список игроков
+ self.ui.StatTable.removeRow(0)
+ rowPosition = 0
+ for user in self.database.getBase(DatabaseName='users'):
+ self.ui.StatTable.insertRow(rowPosition)
+ self.ui.StatTable.setItem(rowPosition, 0, QTableWidgetItem(user["username"]))
+ self.ui.StatTable.setItem(rowPosition, 1, QTableWidgetItem(str(user["points"])))
+ self.ui.StatTable.setItem(rowPosition, 2, QTableWidgetItem(str(user["minesDefuse"])))
+ if user["games"] != 0:
+ st = str(user["minesDefuse"] // user["games"])
+ else:
+ st = '0'
+ self.ui.StatTable.setItem(rowPosition, 3, QTableWidgetItem(st))
+ self.ui.StatTable.setItem(rowPosition, 4, QTableWidgetItem(getGameName(user["lastGame"])))
+
+ rowPosition += 1
+ self.ui.usernamesList.clear()
+ self.accs = list()
+ for user in self.database.getBase(DatabaseName='users'): # Обновляем во вкладке Профили
+ self.ui.usernamesList.addItem(user["username"])
+ self.accs.append(user)
+
+ # Заполним список вариаций сапёра
+ self.ui.gameList.clear()
+ for gameDir in getGamesDict():
+ item = QtWidgets.QListWidgetItem(getGamesDict()[gameDir]['gamename'])
+ icon1 = QtGui.QIcon()
+ icon1.addPixmap(QtGui.QPixmap(f"source/{gameDir}/gameico.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+ item.setIcon(icon1)
+ self.ui.gameList.addItem(item)
+
+ self.show()
+
+ self.ui.usernamesList.doubleClicked.connect(self.importLogin)
+ self.ui.regButton.clicked.connect(self.register)
+ self.ui.loginButton.clicked.connect(self.logIn)
+ self.ui.play.clicked.connect(self.play)
+ self.ui.logOut.clicked.connect(self.logOut)
+ self.ui.updateGames.clicked.connect(self.upDate_sapers)
+ self.ui.loadGame.clicked.connect(self.LoadGame)
+ # Список сохранений...
+ self.ui.SaveList.clear()
+ self.savedGames = list()
+
+ multiMethod = corelib.multiMethod()
+
+ for save in self.database.getBase('gamehashes'):
+ if save['game'] in getGamesDict() and save['userID'] == self.database.getBase('gamedata')[0]['activeprofile']:
+ multiMethod.append(corelib.Method('getGameSession', gamesession=save['hash']))
+
+ resp = multiMethod.start()['responses']
+ respID = -1
+
+ for save in self.database.getBase('gamehashes'):
+ if save['game'] in getGamesDict() and save['userID'] == self.database.getBase('gamedata')[0]['activeprofile']:
+ respID += 1
+ if 'response' in resp[respID]:
+ if resp[respID]['response']['continue']:
+ item = QtWidgets.QListWidgetItem(
+ f"{getGamesDict()[save['game']]['gamename']}, мин: {save['mines']}"
+ )
+ icon1 = QtGui.QIcon()
+ icon1.addPixmap(QtGui.QPixmap(f"source/{save['game']}/gameico.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+ item.setIcon(icon1)
+ self.ui.SaveList.addItem(item)
+ self.savedGames.append([
+ save['hash'],
+ save['mines'],
+ save['game']
+ ])
+
+ # Сделаем таймер
+
+ self.timer = QtCore.QTimer(self)
+ self.timer.timeout.connect(self.timerVoid)
+ self.timer.start(1)
+
+ def upDate_sapers(self):
+ self.ui.gameList.clear()
+ for gameDir in getGamesDict():
+ item = QtWidgets.QListWidgetItem(getGamesDict()[gameDir]['gamename'])
+ icon1 = QtGui.QIcon()
+ icon1.addPixmap(QtGui.QPixmap(f"source/{gameDir}/gameico.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+ item.setIcon(icon1)
+ self.ui.gameList.addItem(item)
+
+ def logOut(self):
+ self.database.setItem(
+ 'activeprofile',
+ '-',
+ 'ID',
+ 1,
+ DatabaseName='gamedata')
+ self.ui.SaveList.clear()
+ QMessageBox.information(self, 'Успех!', 'Вы успешно вышли!!!', QMessageBox.Ok)
+
+ def logIn(self):
+ if self.ui.loginUsernameLine.text() in [user['username'] for user in self.database.getBase('users')]:
+ if SQLEasy.compareKey(self.database.getBase('users'), key='username')[self.ui.loginUsernameLine.text()]['password'] is None:
+ self.database.setItem(
+ 'activeprofile',
+ SQLEasy.compareKey(self.database.getBase('users'), key='username')[self.ui.loginUsernameLine.text()]['ID'],
+ 'ID',
+ 1,
+ DatabaseName='gamedata')
+ QMessageBox.information(self, 'Успех!', 'Вы успешно вошли!!!', QMessageBox.Ok)
+ elif SQLEasy.compareKey(self.database.getBase('users'), key='username')[self.ui.loginUsernameLine.text()]['password'] == self.ui.loginHasloLine.text():
+ self.database.setItem(
+ 'activeprofile',
+ SQLEasy.compareKey(self.database.getBase('users'), key='username')[self.ui.loginUsernameLine.text()]['ID'],
+ 'ID',
+ 1,
+ DatabaseName='gamedata')
+ QMessageBox.information(self, 'Успех!', 'Вы успешно вошли!!!', QMessageBox.Ok)
+ else:
+ QMessageBox.critical(self, 'Упс...', 'Неверный пароль!', QMessageBox.Ok)
+ else:
+ QMessageBox.critical(self, 'Упс...', 'Такого пользователя просто нет :(', QMessageBox.Ok)
+
+ self.ui.SaveList.clear()
+ self.savedGames = list()
+
+ multiMethod = corelib.multiMethod()
+
+ for save in self.database.getBase('gamehashes'):
+ if save['game'] in getGamesDict() and save['userID'] == self.database.getBase('gamedata')[0]['activeprofile']:
+ multiMethod.append(corelib.Method('getGameSession', gamesession=save['hash']))
+
+ resp = multiMethod.start()['responses']
+ respID = -1
+
+ for save in self.database.getBase('gamehashes'):
+ if save['game'] in getGamesDict() and save['userID'] == self.database.getBase('gamedata')[0]['activeprofile']:
+ respID += 1
+ if 'response' in resp[respID]:
+ if resp[respID]['response']['continue']:
+ item = QtWidgets.QListWidgetItem(
+ f"{getGamesDict()[save['game']]['gamename']}, мин: {save['mines']}"
+ )
+ icon1 = QtGui.QIcon()
+ icon1.addPixmap(QtGui.QPixmap(f"source/{save['game']}/gameico.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+ item.setIcon(icon1)
+ self.ui.SaveList.addItem(item)
+ self.savedGames.append([
+ save['hash'],
+ save['mines'],
+ save['game']
+ ])
+
+ def register(self):
+ if self.ui.regLoginLine.text() in [user['username'] for user in self.database.getBase('users')]:
+ QMessageBox.critical(self, 'Упс...', 'Есть такой пользователь, ЕСТЬ!!!', QMessageBox.Ok)
+ return
+ if len(self.ui.regHasloLine.text()) > 0:
+ if len(self.ui.regHasloLine.text()) >= 65:
+ QMessageBox.warning(self, 'Warning!', 'Too many symbols on password!', QMessageBox.Ok)
+ return
+
+ if len(self.ui.regLoginLine.text()) >= 65:
+ QMessageBox.warning(self, 'Warning!', 'Too many symbols on login!', QMessageBox.Ok)
+ return
+
+ self.database.add({
+ "ID": len(self.database.getBase('users')),
+ "username": self.ui.regLoginLine.text()
+ }, 'users')
+ QMessageBox.information(self, 'Успех!', 'Профиль создан!', QMessageBox.Ok)
+
+ self.ui.usernamesList.clear()
+ self.accs = list()
+ for user in self.database.getBase(DatabaseName='users'): # Обновляем во вкладке Профили
+ self.ui.usernamesList.addItem(user["username"])
+ self.accs.append(user)
+
+ def importLogin(self):
+ if self.ui.usernamesList.currentRow() >= 0 and self.ui.usernamesList.currentRow() < len(self.ui.usernamesList):
+ user = self.accs[self.ui.usernamesList.currentRow()]
+ self.ui.loginUsernameLine.setText(user['username'])
+
+ def LoadGame(self):
+ global game
+
+ self.hide()
+ hashK = self.savedGames[self.ui.SaveList.currentRow()][0]
+ mines = self.savedGames[self.ui.SaveList.currentRow()][1]
+
+ game(
+ self.savedGames[self.ui.SaveList.currentRow()][2],
+ gamerID=self.database.getBase('gamedata')[0]['activeprofile'],
+ databaseObj=self.database,
+ gamehash=hashK,
+ MINES=mines,
+ muzicOn=self.ui.soundOn.isChecked()
+ )
+ os.abort()
+ del self
+
+
+ def play(self):
+ global game
+
+ self.hide()
+ hashK = corelib.newGame(ID=self.database.getBase('gamedata')[0]['activeprofile'], mines=25, fieldsize=10)['response']
+ mines = random.randint(25, 55)
+
+ game(
+ [k for k in getGamesDict()][self.ui.gameList.currentRow()],
+ gamerID=self.database.getBase('gamedata')[0]['activeprofile'],
+ databaseObj=self.database,
+ gamehash=hashK['gamesession'],
+ MINES=mines,
+ muzicOn=self.ui.soundOn.isChecked()
+ )
+ os.abort()
+ del self
+
+ def timerVoid(self):
+ def getCoorectLogin(string):
+ login = ''
+ for symbol in string:
+ if symbol in '0123456789qwertyuiopasdfghjklzxcvbnm_-.' + 'qwertyuiopasdfghjklzxcvbnm'.upper():
+ login += symbol
+ if len(login) > 64:
+ login = login[:64]
+ return login
+
+ self.ui.play.setEnabled(
+ self.ui.gameList.currentRow() >= 0 and
+ self.ui.gameList.currentRow() < len(self.ui.gameList) and
+ not(self.database.getBase('gamedata')[0]['activeprofile'] is None or self.database.getBase('gamedata')[0]['activeprofile'] == '-')
+ )
+
+ self.ui.logOut.setEnabled(not(self.database.getBase('gamedata')[0]['activeprofile'] is None or self.database.getBase('gamedata')[0]['activeprofile'] == '-'))
+ self.ui.loadGame.setEnabled(len(self.ui.SaveList) > 0)
+
+ if not(self.database.getBase('gamedata')[0]['activeprofile'] is None or self.database.getBase('gamedata')[0]['activeprofile'] == '-'):
+ nickname = SQLEasy.compareKey(self.database.getBase('users'), 'ID')
+ nickname = nickname[self.database.getBase('gamedata')[0]['activeprofile']]['username']
+ self.ui.gameinfo.setText(f"Добро пожаловать, {nickname}!")
+ else:
+ self.ui.gameinfo.setText("Войдите или зарегайте профиль, чтобы играть!")
+
+ self.ui.loginButton.setEnabled(
+ len(self.ui.loginUsernameLine.text()) > 8 and (len(self.ui.loginHasloLine.text()) > 8 or len(self.ui.loginHasloLine.text()) == 0)
+ )
+ self.ui.regButton.setEnabled(
+ len(self.ui.regLoginLine.text()) > 8 and (len(self.ui.regHasloLine.text()) > 8 or len(self.ui.regHasloLine.text()) == 0)
+ )
+
+ if self.ui.loginUsernameLine.text() != getCoorectLogin(self.ui.loginUsernameLine.text()):
+ self.ui.loginUsernameLine.setText(getCoorectLogin(self.ui.loginUsernameLine.text()))
+ if self.ui.regLoginLine.text() != getCoorectLogin(self.ui.regLoginLine.text()):
+ self.ui.regLoginLine.setText(getCoorectLogin(self.ui.regLoginLine.text()))
+ if self.ui.loginHasloLine.text() != getCoorectLogin(self.ui.loginHasloLine.text()):
+ self.ui.loginHasloLine.setText(getCoorectLogin(self.ui.loginHasloLine.text()))
+ if self.ui.regHasloLine.text() != getCoorectLogin(self.ui.regHasloLine.text()):
+ self.ui.regHasloLine.setText(getCoorectLogin(self.ui.regHasloLine.text()))
+
+ if self.ui.logPasShow.isChecked():
+ self.ui.loginHasloLine.setEchoMode(QtWidgets.QLineEdit.Normal)
+ else:
+ self.ui.loginHasloLine.setEchoMode(QtWidgets.QLineEdit.Password)
+
+ if self.ui.regPasShow.isChecked():
+ self.ui.regHasloLine.setEchoMode(QtWidgets.QLineEdit.Normal)
+ else:
+ self.ui.regHasloLine.setEchoMode(QtWidgets.QLineEdit.Password)
+
+ # Запрещаем редактировать стату
+ self.ui.StatTable.setRowCount(0)
+ rowPosition = 0
+ for user in sorted(self.database.getBase(DatabaseName='users'), key=lambda x: x['points'], reverse=True):
+ self.ui.StatTable.insertRow(rowPosition)
+ self.ui.StatTable.setItem(rowPosition, 0, QTableWidgetItem(user["username"]))
+ self.ui.StatTable.setItem(rowPosition, 1, QTableWidgetItem(str(user["points"])))
+ self.ui.StatTable.setItem(rowPosition, 2, QTableWidgetItem(str(user["minesDefuse"])))
+
+ if user["games"] != 0:
+ st = str(user["minesDefuse"] // user["games"])
+ else:
+ st = '0'
+ self.ui.StatTable.setItem(rowPosition, 3, QTableWidgetItem(st))
+ self.ui.StatTable.setItem(rowPosition, 4, QTableWidgetItem(getGameName(user["lastGame"])))
+
+ rowPosition += 1
+
+
+app = QApplication([])
+application = app_win()
+app.exec()
+os.abort()
\ No newline at end of file
diff --git a/gameDataBase.db b/gameDataBase.db
new file mode 100644
index 0000000000000000000000000000000000000000..d53e4e8b8940b039014af2459ef1ec3adc828d04
GIT binary patch
literal 118784
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