]> bicyclesonthemoon.info Git - ott/molpy-up/commitdiff
start with Molpy Down!
authorb <rowerynaksiezycu@gmail.com>
Thu, 26 Mar 2026 23:09:40 +0000 (00:09 +0100)
committerb <rowerynaksiezycu@gmail.com>
Fri, 27 Mar 2026 00:50:13 +0000 (01:50 +0100)
assets/platformFrame1.png [new file with mode: 0644]
molpydown.py [new file with mode: 0644]
molpyup.py

diff --git a/assets/platformFrame1.png b/assets/platformFrame1.png
new file mode 100644 (file)
index 0000000..591ff89
Binary files /dev/null and b/assets/platformFrame1.png differ
diff --git a/molpydown.py b/molpydown.py
new file mode 100644 (file)
index 0000000..23a2e97
--- /dev/null
@@ -0,0 +1,856 @@
+# -*- coding: utf-8 -*-
+# Molpy Down!
+#
+# Based on Max00355's version of DoodleJump, <https://github.com/Max00355/DoodleJump>
+# Copyright (C) 2015 by Frankie Primerano,
+# written in 120 minutes, see <https://www.reddit.com/r/gamedev/comments/3umhuq/doodle_jump_created_in_120_minutes_with_python/>.
+#
+# Copyright (C) 2018 by Peter Gerwinski <http://www.peter.gerwinski.de>,
+# OTTified in about 120 minutes.
+#
+# Copyright (C) 2018, 2026 by Balthasar SzczepaƄski
+# add arrow, AI, flag save mode,
+# remove off-screen space,
+# gmae mode messages,
+# some optimisation
+# Change into Molpy Down game!
+#
+# This program is Free Software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License (GNU GPL), version 3,
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program, see the file LICENSE.  If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# The player figure "Molpy" is
+# Copyright (C) 2013 by BlitzGirl, see user "BlitzGirl" at <http://forums.xkcd.com>,
+# released under conditions compatible with both the GNU GPL v3 and the
+# CC BY-NC 2.5 license (see below).
+#
+# All other artwork used by this program is based on xkcd 1190 "Time",
+# Copyright (C) 2013 by Randall Munroe, see <http://xkcd.com/1190>,
+# released under the Creative Commonns Attribution-NonCommercial Generic License,
+# version 2.5 (CC BY-NC 2.5), see <https://creativecommons.org/licenses/by-nc/2.5/>.
+#
+# In particular, the contents of the directory "assets"
+# is NOT subject to the GNU GPL.
+
+import pygame
+from pygame.locals import *
+import sys
+import datetime
+import random
+import math
+
+class MolpyUp:
+
+    platformTypeSand       =  0
+    platformTypeGrass      =  1
+    platformTypeNormal     = platformTypeGrass
+    platformTypeGrapevine  =  2
+    platformTypeAfterLucky =  3
+    platformTypeCastle     =  4
+    platformTypeWater      =  5
+    platformTypeRaftcastle =  6
+    platformTypeFloating   = platformTypeRaftcastle
+    platformTypeLucky      =  7
+    platformTypeBreaking   =  8
+    platformTypeTheEnd     =  9
+    platformTypeWonTheGame = 10
+    platformTypeFrame1     = 11
+
+    itemTypeAccelerator = 0
+    itemTypeBeanie      = 1
+    itemTypeSnake       = 2
+    itemTypePrickly     = 3
+    itemTypeSandcastle  = 4
+    itemTypeFlag        = 5
+    itemTypePlantSand   = 6
+    itemTypePlantGrass  = 7
+
+    scoreSnake      = 1738
+    scorePrickly    = 2015
+    scoreGrass      = 2193
+    scoreAfterLucky = 2315
+    scoreCastle     = 2825
+    scoreLucky      = 2976
+    scoreRaftcastle = 3031
+    scoreWater      = 3043
+    scoreTheEnd     = 3089
+    scoreEpilogue   = 3094
+
+    def __init__(self):
+        self.relativeX=0
+        self.sx = 553
+        self.sy = 395
+        self.extrax = self.sx // 16
+        self.screen = pygame.display.set_mode((self.sx, self.sy))
+        pygame.font.init()
+        self.font = pygame.font.SysFont("xkcd,sans", 25)
+        self.clock = pygame.time.Clock()
+        self.xmovementmax = 10
+        self.eternal = False
+        self.eternalFlag = False
+        self.ai = False
+        self.aiDebag = False
+        self.imgPlatformSand         = [ pygame.image.load("assets/platformSand1.png").convert_alpha(),
+                                         pygame.image.load("assets/platformSand2.png").convert_alpha(),
+                                         pygame.image.load("assets/platformSand3.png").convert_alpha(),
+                                         pygame.image.load("assets/platformSand4.png").convert_alpha() ]
+        self.imgPlatformGrass        = [ pygame.image.load("assets/platformGrass1.png").convert_alpha(),
+                                         pygame.image.load("assets/platformGrass2.png").convert_alpha(),
+                                         pygame.image.load("assets/platformGrass3.png").convert_alpha(),
+                                         pygame.image.load("assets/platformGrass1f.png").convert_alpha(),
+                                         pygame.image.load("assets/platformGrass2f.png").convert_alpha(),
+                                         pygame.image.load("assets/platformGrass3f.png").convert_alpha() ]
+        self.imgPlatformWater        = [ pygame.image.load("assets/platformWater1.png").convert_alpha(),
+                                         pygame.image.load("assets/platformWater2.png").convert_alpha(),
+                                         pygame.image.load("assets/platformWater1f.png").convert_alpha(),
+                                         pygame.image.load("assets/platformWater2f.png").convert_alpha() ]
+        self.imgPlatformAfterLucky     = pygame.image.load("assets/platformAfterLucky.png").convert_alpha()
+        self.imgPlatformCastle         = pygame.image.load("assets/platformCastle.png").convert_alpha()
+        self.imgPlatformLuckySleeping  = pygame.image.load("assets/platformLuckySleeping.png").convert_alpha()
+        self.imgPlatformLuckyAttacking = pygame.image.load("assets/platformLuckyAttacking.png").convert_alpha()
+        self.imgPlatformRaftcastle     = pygame.image.load("assets/platformRaftcastle.png").convert_alpha()
+        self.imgPlatformGrapevine      = pygame.image.load("assets/platformGrapevine.png").convert_alpha()
+        self.imgPlatformBreaking       = pygame.image.load("assets/platformBreaking.png").convert_alpha()
+        self.imgPlatformBroken         = pygame.image.load("assets/platformBroken.png").convert_alpha()
+        self.imgPlatformTheEnd         = pygame.image.load("assets/platformTheEnd.png").convert_alpha()
+        self.imgPlatformWonTheGame     = pygame.image.load("assets/platformWonTheGame.png").convert_alpha()
+        self.imgPlatformFrame1         = pygame.image.load("assets/platformFrame1.png").convert_alpha()
+        self.imgPlayerRightUp          = pygame.image.load("assets/playerRightUp.png").convert_alpha()
+        self.imgPlayerRightDown        = pygame.image.load("assets/playerRightDown.png").convert_alpha()
+        self.imgPlayerLeftUp           = pygame.image.load("assets/playerLeftUp.png").convert_alpha()
+        self.imgPlayerLeftDown         = pygame.image.load("assets/playerLeftDown.png").convert_alpha()
+        self.imgPlayerRightUpBeanie    = pygame.image.load("assets/playerRightUpBeanie.png").convert_alpha()
+        self.imgPlayerRightDownBeanie  = pygame.image.load("assets/playerRightDownBeanie.png").convert_alpha()
+        self.imgPlayerLeftUpBeanie     = pygame.image.load("assets/playerLeftUpBeanie.png").convert_alpha()
+        self.imgPlayerLeftDownBeanie   = pygame.image.load("assets/playerLeftDownBeanie.png").convert_alpha()
+        self.imgAccelerator            = pygame.image.load("assets/accelerator.png").convert_alpha()
+        self.imgAcceleratorUsed        = pygame.image.load("assets/acceleratorUsed.png").convert_alpha()
+        self.imgBeanie                 = pygame.image.load("assets/beanie.png").convert_alpha()
+        self.imgSnake                  = pygame.image.load("assets/snake.png").convert_alpha()
+        self.imgSnakeLeft              = pygame.image.load("assets/snakeLeft.png").convert_alpha()
+        self.imgSnakeRight             = pygame.image.load("assets/snakeRight.png").convert_alpha()
+        self.imgPrickly                = pygame.image.load("assets/prickly.png").convert_alpha()
+        self.imgPricklyCurled          = pygame.image.load("assets/pricklyCurled.png").convert_alpha()
+        self.imgSandcastle             = pygame.image.load("assets/sandcastle.png").convert_alpha()
+        self.imgFlagLeft               = pygame.image.load("assets/flagLeft.png").convert_alpha()
+        self.imgFlagLeftDown           = pygame.image.load("assets/flagLeftDown.png").convert_alpha()
+        self.imgFlagRight              = pygame.image.load("assets/flagRight.png").convert_alpha()
+        self.imgFlagRightDown          = pygame.image.load("assets/flagRightDown.png").convert_alpha()
+        self.imgPlantSand            = [ pygame.image.load("assets/plantSand1.png").convert_alpha(),
+                                         pygame.image.load("assets/plantSand2.png").convert_alpha(),
+                                         pygame.image.load("assets/plantSand3.png").convert_alpha(),
+                                         pygame.image.load("assets/plantSand4.png").convert_alpha(),
+                                         pygame.image.load("assets/plantSand5.png").convert_alpha() ]
+        self.imgPlantGrass           = [ pygame.image.load("assets/plantGrass1.png").convert_alpha(),
+                                         pygame.image.load("assets/plantGrass2.png").convert_alpha(),
+                                         pygame.image.load("assets/plantGrass3.png").convert_alpha(),
+                                         pygame.image.load("assets/plantGrass4.png").convert_alpha(),
+                                         pygame.image.load("assets/plantGrass5.png").convert_alpha(),
+                                         pygame.image.load("assets/plantGrass6.png").convert_alpha(),
+                                         pygame.image.load("assets/plantGrass7.png").convert_alpha(),
+                                         pygame.image.load("assets/plantGrass8.png").convert_alpha(),
+                                         pygame.image.load("assets/plantGrass9.png").convert_alpha(),
+                                         pygame.image.load("assets/plantGrass10.png").convert_alpha(),
+                                         pygame.image.load("assets/plantGrass11.png").convert_alpha() ]
+        self.imgMolpArrow              = pygame.image.load("assets/molpArrow.png").convert_alpha()
+        self.playerHeight = self.imgPlayerRightUp.get_height()
+        # self.playerHalfHeight = self.playerHeight // 2
+        self.playerWidth = self.imgPlayerRightUp.get_width()
+        self.playerHalfWidth = self.playerWidth // 2
+        self.platformSpeed = self.extrax // 10
+        self.platformSandHeight = self.imgPlatformSand[0].get_height()
+        self.platformSandWidth = self.imgPlatformSand[0].get_width()
+        self.showArrow = True
+        
+    def reset(self):
+        self.cameray = 0
+        self.score = self.scoreEpilogue
+        self.sandcastles = 0
+        self.speed = 30
+        self.modeText = ''
+        self.playerx = self.sx // 2 - self.playerHalfWidth
+        self.playery = self.sy * 3 // 4
+        self.direction = 0
+        self.jump = 0
+        self.gravity = 0
+        self.xmovement = 0
+        self.playerWearsBeanie = False
+        self.playerCarriesFlag = False
+        self.hadSnake = False
+        self.hadPrickly = False
+        self.hadAfterLucky = False
+        self.hadCastle = False
+        self.hadLucky = False
+        self.hadTheEnd = False
+        self.raftcastleHasFlag = False
+        self.platforms = [
+            [self.sx // 2 - self.imgPlatformWonTheGame.get_width() // 2, self.playery - self.sy // 2, self.platformTypeWonTheGame, False, False, -1, 0, self.imgPlatformWonTheGame.get_width()],
+            [self.sx // 2 - self.imgPlatformTheEnd.get_width() // 2, self.playery + self.sy // 6, self.platformTypeTheEnd, False, False, -1, 0, self.imgPlatformTheEnd.get_width()]
+        ]
+        self.generateInitialPlatforms()
+        self.items = []
+        self.aiNextPlatformOk = False
+        self.aiNextPlatform=[self.playerx,self.playery]
+        self.oops = False
+        self.pause = False
+        if self.filename:
+            self.restoreGame (self.filename)
+
+    def saveGame(self):
+        self.filename = datetime.datetime.now().strftime("%Y%m%d-%H%M%S.molpyup")
+        with open(self.filename, "w") as file:
+            file.write("MolpyUp!\n")
+            file.write("cameray: " + str(self.cameray) + "\n")
+            file.write("score: " + str(self.score) + "\n")
+            file.write("sandcastles: " + str(self.sandcastles) + "\n")
+            file.write("speed: " + str(self.speed) + "\n")
+            file.write("showArrow: " + str(self.showArrow) + "\n")
+            file.write("playerx: " + str(self.playerx) + "\n")
+            file.write("playery: " + str(self.playery) + "\n")
+            file.write("direction: " + str(self.direction) + "\n")
+            file.write("jump: " + str(self.jump) + "\n")
+            file.write("gravity: " + str(self.gravity) + "\n")
+            file.write("xmovement: " + str(self.xmovement) + "\n")
+            file.write("playerWearsBeanie: " + str(self.playerWearsBeanie) + "\n")
+            file.write("playerCarriesFlag: " + str(self.playerCarriesFlag) + "\n")
+            file.write("hadSnake: " + str(self.hadSnake) + "\n")
+            file.write("hadPrickly: " + str(self.hadPrickly) + "\n")
+            file.write("hadAfterLucky: " + str(self.hadAfterLucky) + "\n")
+            file.write("hadCastle: " + str(self.hadCastle) + "\n")
+            file.write("hadLucky: " + str(self.hadLucky) + "\n")
+            file.write("hadTheEnd: " + str(self.hadTheEnd) + "\n")
+            file.write("raftcastleHasFlag: " + str(self.raftcastleHasFlag) + "\n")
+            file.write("eternal: " + str(self.eternal) + "\n")
+            file.write("eternalFlag: " + str(self.eternalFlag) + "\n")
+            file.write("platforms: " + str(self.platforms) + "\n")
+            file.write("items: " + str(self.items) + "\n")
+
+    def readVariable(self, line, name, var):
+        if line.startswith(name + ": "):
+            return eval (line[len(name) + 2:])
+        else:
+            return var
+
+    def restoreGame(self, filename):
+        try:
+            with open(filename, "r") as file:
+                lines = file.readlines()
+            for line in lines:
+                self.cameray = self.readVariable(line, "cameray", self.cameray)
+                self.score = self.readVariable(line, "score", self.score)
+                self.sandcastles = self.readVariable(line, "sandcastles", self.sandcastles)
+                self.speed = self.readVariable(line, "speed", self.speed)
+                self.showArrow = self.readVariable(line, "showArrow", self.showArrow)
+                self.playerx = self.readVariable(line, "playerx", self.playerx)
+                self.playery = self.readVariable(line, "playery", self.playery)
+                self.direction = self.readVariable(line, "direction", self.direction)
+                self.jump = self.readVariable(line, "jump", self.jump)
+                self.gravity = self.readVariable(line, "gravity", self.gravity)
+                self.xmovement = self.readVariable(line, "xmovement", self.xmovement)
+                self.playerWearsBeanie = self.readVariable(line, "playerWearsBeanie", self.playerWearsBeanie)
+                self.playerCarriesFlag = self.readVariable(line, "playerCarriesFlag", self.playerCarriesFlag)
+                self.hadSnake = self.readVariable(line, "hadSnake", self.hadSnake)
+                self.hadPrickly = self.readVariable(line, "hadPrickly", self.hadPrickly)
+                self.hadAfterLucky = self.readVariable(line, "hadAfterLucky", self.hadAfterLucky)
+                self.hadCastle = self.readVariable(line, "hadCastle", self.hadCastle)
+                self.hadLucky = self.readVariable(line, "hadLucky", self.hadLucky)
+                self.hadTheEnd = self.readVariable(line, "hadTheEnd", self.hadTheEnd)
+                self.raftcastleHasFlag = self.readVariable(line, "raftcastleHasFlag", self.raftcastleHasFlag)
+                self.platforms = self.readVariable(line, "platforms", self.platforms)
+                self.items = self.readVariable(line, "items", self.items)
+            return True
+        except FileNotFoundError:
+            return False
+
+    def findNextPlatform(self):
+        bestPlatformScore = float("-Inf")
+        actualY = self.playery + self.playerHeight
+        actualX = self.playerx + self.playerHalfWidth
+        self.aiNextPlatform = self.platforms[0]
+        if self.jump > 0:
+            maxY = actualY - (self.jump * (self.jump + 1 ) // 2)
+            framesUp = self.jump
+        else:
+            maxY = actualY
+            framesUp = 0
+               
+        for p in self.platforms:
+            platformX = p[0] + p[7] //2
+            platformY = p[1]
+            platformScore = 0
+           
+            if (platformY < maxY) or (p[2] == self.platformTypeBreaking):
+                platformScore = float("-Inf")
+                p[6] = platformScore
+                continue
+           
+            distY = actualY - platformY
+            distDown = platformY - maxY
+            distX = abs(platformX-actualX)
+           
+            if self.gravity > 0:
+                framesDown = int(math.floor(math.sqrt(self.gravity * self.gravity + 2 * distDown) - self.gravity))
+            else:
+                framesDown = int(math.floor(math.sqrt(2*distDown)))
+           
+            speedX = 9;
+           
+            if p[2] > self.platformTypeNormal and p[2] <= self.platformTypeFloating:
+                if (p[4] and platformX > actualX) or (not p[4] and platformX < actualX):
+                    speedX -= self.platformSpeed
+                else:
+                    speedX += self.platformSpeed
+           
+            platformScore += framesUp + framesDown - distX // speedX
+           
+            if platformX - actualX > 2 * self.xmovementmax and self.xmovement < 0:
+                platformScore -= (self.xmovementmax - self.xmovement) * (self.xmovementmax - self.xmovement) // 4
+            elif actualX - platformX > 2 * self.xmovementmax and self.xmovement > 0:
+                platformScore -= (-self.xmovementmax - self.xmovement) * (-self.xmovementmax - self.xmovement) // 4
+           
+            if platformScore < 0:
+                platformScore = float("-Inf")
+            platformScore *= 4 
+           
+            if distY > 16:
+                platformScore += distY + distX // 2
+            else:
+                platformScore += 2 * distY - 200 + distX
+           
+            if p[2] > self.platformTypeNormal and p[2] <= self.platformTypeFloating:
+                platformScore -= 50 #100
+            elif p[2] == self.platformTypeLucky:
+                platformScore -= 150
+           
+            if p[5] == self.itemTypeSnake:
+                platformScore -= 150
+            elif p[5] == self.itemTypeFlag and not self.playerCarriesFlag:
+                platformScore += 70
+            elif p[5] == self.itemTypeSandcastle and self.playerCarriesFlag:
+                platformScore += 70
+            elif p[5] == self.itemTypeBeanie and not self.playerWearsBeanie:
+                platformScore += 50
+           
+            p[6] = platformScore
+           
+            if platformScore > bestPlatformScore:
+                bestPlatformScore = platformScore
+                self.aiNextPlatform = p
+                self.aiNextPlatformOk = True
+
+    def updatePlayer(self):
+        if ((not self.jump) and (self.playery > self.aiNextPlatform[1])) or (self.aiNextPlatform[1] - self.cameray > self.sy):
+            self.aiNextPlatformOk = False
+        
+        if not self.aiNextPlatformOk and self.ai:
+            self.findNextPlatform()
+         
+        if not self.jump:
+            self.playery += self.gravity
+            self.gravity += 1
+        else:
+            self.playery -= self.jump
+            self.jump -= 1
+            
+        if self.playery - self.cameray > self.sy * 7 // 6:
+            if self.eternal or (self.eternalFlag and self.sandcastles > 0):
+                if self.eternalFlag:
+                    self.sandcastles -= 1
+                self.jump = self.gravity
+                self.gravity = 0
+                self.aiNextPlatformOk = False
+                self.playery = self.cameray + self.sy + self.playerHeight
+            else:
+                self.oops = True
+        
+        key = pygame.key.get_pressed()
+        
+        xdir = 0;
+        actualX = self.playerx + self.playerHalfWidth
+        if key[K_RIGHT]:
+            xdir = 1
+            self.modeText = ''
+        elif key[K_LEFT]:
+            xdir = -1
+            self.modeText = ''
+        elif key[K_PLUS] or key[K_KP_PLUS]:
+            if pygame.key.get_mods() & KMOD_CTRL:
+                self.score += 10
+                self.modeText = "Score +10: " + str(self.score)
+            else:
+                self.speed += 1
+                self.modeText = "Speed: " + str(self.speed)
+        elif key[K_MINUS] or key[K_KP_MINUS]:
+            if pygame.key.get_mods() & KMOD_CTRL:
+                self.score -= 10
+                self.modeText = "Score -10: " + str(self.score)
+            else:
+                self.speed -= 1
+                self.modeText = "Speed: " + str(self.speed)
+        elif self.ai:
+            platformX = self.aiNextPlatform[0] + self.aiNextPlatform[7] // 2
+            if self.aiNextPlatform[2] > self.platformTypeNormal and self.aiNextPlatform[2] <= self.platformTypeFloating:
+                if self.aiNextPlatform[4] == True:
+                    self.relativeX = self.xmovement - self.platformSpeed
+                else:
+                    self.relativeX = self.xmovement + self.platformSpeed
+            else:
+                self.relativeX = self.xmovement
+
+            if actualX < platformX - 2.5 * self.relativeX:
+                xdir = 1
+            elif actualX > platformX - 2.5 * self.relativeX:
+                xdir = -1
+        
+        if xdir > 0:
+            if self.xmovement < self.xmovementmax:
+                self.xmovement += 1
+            elif self.xmovement > self.xmovementmax:
+                self.xmovement -= 1
+            self.direction = 0
+        elif xdir < 0:
+            if self.xmovement > -self.xmovementmax:
+                self.xmovement -= 1
+            elif self.xmovement < -self.xmovementmax:
+                self.xmovement += 1
+            self.direction = 1
+        elif self.xmovement > 0:
+            self.xmovement -= 1
+        elif self.xmovement < 0:
+            self.xmovement += 1
+        
+        self.playerx += self.xmovement
+        actualX += self.xmovement
+        
+        while actualX < 0:
+            self.playerx += self.sx
+            actualX += self.sx
+            self.aiNextPlatformOk = False
+        while actualX >= self.sx:
+            self.playerx -= self.sx
+            actualX -= self.sx
+            self.aiNextPlatformOk = False
+        
+        if self.playery - self.cameray >= self.sy // 3:
+            if self.jump:
+                self.cameray += self.sy // 120
+            else:
+                self.cameray += self.sy // 180
+
+        drawX = self.playerx % self.sx
+        if drawX > self.sx - self.playerWidth:
+            drawX = [drawX, drawX - self.sx]
+        else:
+            drawX = [drawX]
+        drawY = self.playery - self.cameray
+        
+        for x in drawX:
+            if (drawY + self.playerHeight) < 0:
+                if self.showArrow:
+                    self.screen.blit(self.imgMolpArrow, (x, 2))
+            else:
+                if not self.direction:
+                    if self.jump:
+                        if self.playerWearsBeanie:
+                            self.screen.blit(self.imgPlayerRightDownBeanie, (x, drawY))
+                        else:
+                            self.screen.blit(self.imgPlayerRightDown, (x, drawY))
+                        if self.playerCarriesFlag:
+                            self.screen.blit(self.imgFlagLeft, (x + 24, drawY - 10))
+                    else:
+                        if self.playerWearsBeanie:
+                            self.screen.blit(self.imgPlayerRightUpBeanie, (x, drawY))
+                        else:
+                            self.screen.blit(self.imgPlayerRightUp, (x, drawY))
+                        if self.playerCarriesFlag:
+                            self.screen.blit(self.imgFlagLeftDown, (x + 22, drawY - 10))
+                else:
+                    if self.jump:
+                        if self.playerWearsBeanie:
+                            self.screen.blit(self.imgPlayerLeftDownBeanie, (x, drawY))
+                        else:
+                            self.screen.blit(self.imgPlayerLeftDown, (x, drawY))
+                        if self.playerCarriesFlag:
+                            self.screen.blit(self.imgFlagRight, (x + 13, drawY - 10))
+                    else:
+                        if self.playerWearsBeanie:
+                            self.screen.blit(self.imgPlayerLeftUpBeanie, (x, drawY))
+                        else:
+                            self.screen.blit(self.imgPlayerLeftUp, (x, drawY))
+                        if self.playerCarriesFlag:
+                            self.screen.blit(self.imgFlagRightDown, (x + 11, drawY - 10))
+
+    def choosePlatformType(self):
+        platformType = random.randint(0, 999)
+        if self.score > self.scoreWater:
+            if platformType < 900:
+                return self.platformTypeWater
+            else:
+                return self.platformTypeRaftcastle
+        elif platformType < 800:
+            if platformType < 1000 * self.score // self.scoreGrass:
+                if self.score <= self.scoreLucky and not self.hadLucky:
+                    self.hadLucky = True
+                    return self.platformTypeLucky
+                elif self.score <= self.scoreCastle and not self.hadCastle:
+                    self.hadCastle = True
+                    return self.platformTypeCastle
+                elif self.score <= self.scoreAfterLucky and not self.hadAfterLucky:
+                    self.hadAfterLucky = True
+                    return self.platformTypeAfterLucky
+                else:
+                    return self.platformTypeGrass
+            else:
+                return self.platformTypeSand
+        elif platformType < 900:
+            return self.platformTypeGrapevine
+        else:
+            return self.platformTypeBreaking
+
+    def generateNewPlatform(self):
+        platform = False
+        platformType = self.choosePlatformType()
+        if platformType == self.platformTypeWater or platformType == self.platformTypeRaftcastle:
+            platform = [random.randint(0, self.sx - self.platformSandWidth), self.platforms[-1][1] + self.sy // 6, platformType, False, False, -1, 0, self.platformSandWidth]
+        elif platformType == self.platformTypeLucky:
+            platform = [0, self.platforms[-1][1] + self.sy // 12, platformType, False, False, -1, False, self.platformSandWidth]
+        else:
+            platform = [random.randint(0, self.sx - self.platformSandWidth), self.platforms[-1][1] + self.sy // 9, platformType, False, False, -1, 0, self.platformSandWidth]
+        if platformType <= self.platformTypeNormal:
+            if platformType == self.platformTypeSand:
+                platform[4] = random.randint(0, len(self.imgPlatformSand) - 1)
+            elif platformType == self.platformTypeGrass:
+                platform[4] = random.randint(0, len(self.imgPlatformGrass) - 1)
+            else:
+                platform[4] = random.randint(0, len(self.imgPlatformWater) - 1)
+            x = platform[0]
+            y = platform[1]
+            if platformType == self.platformTypeGrass and self.score > self.scoreSnake and not self.hadSnake:
+                platform[5]=self.itemTypeSnake
+                self.items.append([x - 10, y + 9, self.itemTypeSnake, False])
+                self.hadSnake = True
+            elif platformType == self.platformTypeGrass and self.score > self.scorePrickly and not self.hadPrickly:
+                platform[5]=self.itemTypePrickly
+                self.items.append([x + self.imgPlatformSand[0].get_width() // 3, y + 8, self.itemTypePrickly, False])
+                self.hadPrickly = True
+            elif self.score > 0:
+                check = random.randint(0, 999)
+                if check > 800:
+                    xx = x + random.randint(0, self.platformSandWidth - 40)
+                    itemType = random.randint(0,999)
+                    if itemType < 50:
+                        platform[5]=self.itemTypeBeanie
+                        self.items.append([xx, y + 7, self.itemTypeBeanie, False])
+                    elif itemType < 150 and platformType == self.platformTypeSand:
+                        platform[5]=self.itemTypeSandcastle
+                        self.items.append([xx, y + 7, self.itemTypeSandcastle, False])
+                    elif itemType < 350 and platformType == self.platformTypeSand:
+                        platform[5]=self.itemTypeFlag
+                        self.items.append([xx, y + 7, self.itemTypeFlag, False])
+                    elif itemType < 950 and platformType == self.platformTypeSand:
+                        platform[5]=self.itemTypePlantSand
+                        self.items.append([xx, y + 8, self.itemTypePlantSand, itemType % len(self.imgPlantSand)])
+                    elif itemType < 100 and platformType == self.platformTypeGrass:
+                        platform[5]=self.itemTypeFlag
+                        self.items.append([xx, y + 6, self.itemTypeFlag, False])
+                    elif itemType < 700 and platformType == self.platformTypeGrass:
+                        platform[5]=self.itemTypePlantGrass
+                        self.items.append([xx, y + 10, self.itemTypePlantGrass, itemType % len(self.imgPlantGrass)])
+                    elif itemType < 850 and platformType == self.platformTypeGrass and self.score > self.scorePrickly:
+                        platform[5]=self.itemTypePrickly
+                        self.items.append([xx, y + 8, self.itemTypePrickly, False])
+                    elif itemType < 950 and platformType == self.platformTypeGrass and self.score > self.scoreSnake:
+                        platform[5]=self.itemTypeSnake
+                        self.items.append([x - 10, y + 9, self.itemTypeSnake, False])
+                    else:
+                        platform[5]=self.itemTypeAccelerator
+                        self.items.append([xx - 5, y + 10, self.itemTypeAccelerator, False])
+        if platform != False:
+            self.platforms.append(platform)
+
+    def updatePlatforms(self):
+        while True:
+            if len(self.platforms) < 1:
+                return
+            if self.platforms[0][1] - self.cameray >= - self.platformSandHeight - self.sy // 12:
+                break
+            self.generateNewPlatform()
+            self.platforms.pop(0)
+            if self.score > 1:
+                self.score -= 1
+        for p in self.platforms:
+            rect = pygame.Rect(p[0], p[1], p[7], self.platformSandHeight)
+            colX = self.playerx % self.sx
+            player = pygame.Rect(colX + 15, self.playery, self.playerWidth - 30, self.playerHeight)
+            collision = rect.colliderect(player)
+            if colX > self.sx - self.playerWidth:
+                player = pygame.Rect(colX - self.sx + 15, self.playery, self.playerWidth - 30, self.playerHeight)
+                collision = rect.colliderect(player) or collision
+            if collision and self.gravity:
+                if p[2] == self.platformTypeBreaking:
+                    p[4] = True
+                else:
+                    self.jump = self.sy // 20
+                    self.aiNextPlatformOk = False
+                    self.gravity = 0
+                    if p[2] == self.platformTypeLucky and not (self.playerWearsBeanie and self.playerCarriesFlag) and p[3] <= 0:
+                        self.aiNextPlatformOk = False
+                        self.xmovement = self.sx // 20
+                        self.direction = 0
+                        self.cameray -= self.sy // 12
+                        p[3] = -1
+                    elif (p[2] == self.platformTypeAfterLucky or p[2] == self.platformTypeCastle or p[2] == self.platformTypeLucky) and self.playerCarriesFlag and not p[3]:
+                        self.playerCarriesFlag = False
+                        p[3] = True
+                        self.sandcastles += 1
+                    elif p[2] == self.platformTypeRaftcastle and self.playerCarriesFlag and not self.raftcastleHasFlag:
+                        self.playerCarriesFlag = False
+                        self.raftcastleHasFlag = True
+                        self.sandcastles += 1
+            if p[2] > self.platformTypeNormal and p[2] <= self.platformTypeFloating:
+                if p[4]:
+                    p[0] += self.platformSpeed
+                    if p[0] + p[7] >= self.sx:# + self.extrax:
+                        p[4] = False
+                else:
+                    p[0] -= self.platformSpeed
+                    if p[0] <= 0:
+                        p[4] = True
+
+    def drawPlatforms(self):
+        for p in self.platforms:
+            if p[2] == self.platformTypeSand:
+                self.screen.blit(self.imgPlatformSand[p[4]], (p[0], p[1] - self.cameray))
+            elif p[2] == self.platformTypeGrass:
+                self.screen.blit(self.imgPlatformGrass[p[4]], (p[0], p[1] - self.cameray))
+            elif p[2] == self.platformTypeWater:
+                self.screen.blit(self.imgPlatformWater[p[4]], (p[0], p[1] - self.cameray))
+            elif p[2] == self.platformTypeGrapevine:
+                self.screen.blit(self.imgPlatformGrapevine, (p[0], p[1] - self.cameray))
+            elif p[2] == self.platformTypeAfterLucky:
+                if p[3]:
+                    self.screen.blit(self.imgFlagRight, (p[0] + 47, p[1] - 12 - self.cameray))
+                self.screen.blit(self.imgPlatformAfterLucky, (p[0], p[1] - self.cameray))
+            elif p[2] == self.platformTypeCastle:
+                if p[3]:
+                    self.screen.blit(self.imgFlagRight, (p[0] + self.imgPlatformCastle.get_width() - 16, p[1] - 4 - self.cameray))
+                self.screen.blit(self.imgPlatformCastle, (p[0], p[1] - self.cameray))
+            elif p[2] == self.platformTypeLucky:
+                if p[3]:
+                    self.screen.blit(self.imgPlatformLuckyAttacking, (p[0], p[1] - self.imgPlatformLuckyAttacking.get_height() + self.imgPlatformLuckySleeping.get_height() - self.cameray))
+                    if p[3] > 0:
+                        self.screen.blit(self.imgFlagRight, (p[0] + self.imgPlatformLuckyAttacking.get_width() - 8, p[1] - 11 - self.cameray))
+                else:
+                    self.screen.blit(self.imgPlatformLuckySleeping, (p[0], p[1] - self.cameray))
+            elif p[2] == self.platformTypeRaftcastle:
+                if self.raftcastleHasFlag:
+                    self.screen.blit(self.imgFlagRight, (p[0] + 50, p[1] - 13 - self.cameray))
+                self.screen.blit(self.imgPlatformRaftcastle, (p[0], p[1] - self.cameray))
+            elif p[2] == self.platformTypeBreaking:
+                if not p[4]:
+                    self.screen.blit(self.imgPlatformBreaking, (p[0], p[1] - self.cameray))
+                else:
+                    self.screen.blit(self.imgPlatformBroken, (p[0], p[1] - self.cameray))
+            elif p[2] == self.platformTypeTheEnd:
+                self.screen.blit(self.imgPlatformTheEnd, (p[0], p[1] - self.cameray))
+            elif p[2] == self.platformTypeWonTheGame:
+                self.screen.blit(self.imgPlatformWonTheGame, (p[0], p[1] - self.cameray))
+            if self.aiDebag:
+                self.screen.blit(self.font.render(str(p[2])+" "+str(p[5])+" "+str(p[6]), -1, (0, 0x57, 0xaf) if self.ai else (0xbb, 0x66, 0x22)), (p[0], p[1] - self.cameray + 16))
+        if self.aiDebag:
+            self.screen.blit(self.imgMolpArrow, (self.aiNextPlatform[0] + (self.platformSandWidth-self.playerWidth)//2, self.aiNextPlatform[1] - self.cameray + 16))
+
+    def drawAndUpdateItems(self):
+        while self.items and self.items[0][1] - self.cameray > self.sy + self.sy // 12:
+            self.items.pop(0)
+        for item in self.items:
+            if item[2] == self.itemTypeAccelerator:
+                if item[-1]:
+                    imgItem = self.imgAcceleratorUsed
+                else:
+                    imgItem = self.imgAccelerator
+            elif item[2] == self.itemTypeBeanie:
+                if not item[-1]:
+                    imgItem = self.imgBeanie
+                else:
+                    imgItem = None
+            elif item[2] == self.itemTypeSnake:
+                if item[-1] == -1:
+                    imgItem = self.imgSnakeLeft
+                elif item[-1] == 1:
+                    imgItem = self.imgSnakeRight
+                else:
+                    imgItem = self.imgSnake
+            elif item[2] == self.itemTypePrickly:
+                if not item[-1]:
+                    imgItem = self.imgPrickly
+                else:
+                    imgItem = self.imgPricklyCurled
+            elif item[2] == self.itemTypeSandcastle:
+                imgItem = self.imgSandcastle
+                if item[-1]:
+                    self.screen.blit(self.imgFlagRight, (item[0] + 4, item[1] - imgItem.get_height() + 2 - self.imgFlagRight.get_height() - self.cameray))
+            elif item[2] == self.itemTypeFlag:
+                if not item[-1]:
+                    imgItem = self.imgFlagRight
+                else:
+                    imgItem = None
+            elif item[2] == self.itemTypePlantSand:
+                imgItem = self.imgPlantSand[item[-1]]
+            elif item[2] == self.itemTypePlantGrass:
+                imgItem = self.imgPlantGrass[item[-1]]
+            if imgItem:
+                self.screen.blit(imgItem, (item[0], item[1] - imgItem.get_height() - self.cameray))
+            if not item[-1]:
+                if pygame.Rect(item[0], item[1] - imgItem.get_height(), imgItem.get_width(), imgItem.get_height()).colliderect(pygame.Rect(self.playerx, self.playery, self.imgPlayerRightUp.get_width(), self.imgPlayerRightUp.get_height())):
+                    if item[2] == self.itemTypeAccelerator:
+                        self.aiNextPlatformOk = False
+                        self.jump = self.sy // 12
+                        self.cameray -= self.sy // 12
+                        item[-1] = True
+                    elif item[2] == self.itemTypeBeanie and not self.playerWearsBeanie:
+                        self.playerWearsBeanie = True
+                        item[-1] = True
+                    elif item[2] == self.itemTypeSnake:
+                        self.aiNextPlatformOk = False
+                        if self.playerx + self.imgPlayerRightUp.get_width() // 2 < item[0] + self.imgPlatformGrass[0].get_width() // 2:
+                            self.xmovement = -self.sx // 30
+                            self.direction = 0
+                            self.cameray -= self.sy // 12
+                            item[-1] = -1
+                        else:
+                            self.xmovement = self.sx // 30
+                            self.direction = 0
+                            self.cameray -= self.sy // 12
+                            item[-1] = 1
+                    elif item[2] == self.itemTypePrickly:
+                        item[-1] = True
+                    elif item[2] == self.itemTypeSandcastle and self.playerCarriesFlag:
+                        self.playerCarriesFlag = False
+                        item[-1] = True
+                        self.sandcastles += 1
+                    elif item[2] == self.itemTypeFlag and not self.playerCarriesFlag:
+                        self.playerCarriesFlag = True
+                        item[-1] = True
+
+    def generateInitialPlatforms(self):
+        while self.platforms[-1][1] < self.sy * 10 // 6:
+            self.generateNewPlatform()
+
+    def drawGrid(self):
+        for x in range(80):
+            pygame.draw.line(self.screen, (222,222,222), (x * 12, 0), (x * 12, self.sy))
+            pygame.draw.line(self.screen, (222,222,222), (0, x * 12), (self.sx, x * 12))
+
+    def waitForIt(self, its):
+        run = False
+        while not run:
+            self.clock.tick(self.speed)
+            event = pygame.event.poll()
+            if event.type == KEYDOWN:
+                key = pygame.key.get_pressed()
+                if key[K_ESCAPE]:
+                    sys.exit()
+                for it in its:
+                    if key[it]:
+                        return it
+
+    def showScore(self):
+        line1 = self.font.render("Press ENTER to restart,", -1, (0, 0, 0))
+        line2 = self.font.render("ESC to quit.", -1, (0, 0, 0))
+        w = max(line1.get_width(), line2.get_width())
+        h = line1.get_height() + line2.get_height()
+        dx = 10
+        dy = 5
+        pygame.draw.rect(self.screen, (255,255,255), ((self.sx - w) // 2 - dx, (self.sy - h) // 2 - dy, w + 2 * dx, h + 2 * dy))
+        pygame.draw.rect(self.screen, (0,0,0), ((self.sx - w) // 2 - dx, (self.sy - h) // 2 - dy, w + 2 * dx, h + 2 * dy), 3)
+        self.screen.blit(line1, ((self.sx - line1.get_width()) // 2, self.sy // 2 - line1.get_height()))
+        self.screen.blit(line2, ((self.sx - line2.get_width()) // 2, self.sy // 2))
+        pygame.display.flip()
+        self.waitForIt([K_RETURN])
+
+    def run(self):
+        if len(sys.argv) > 1:
+            self.filename = sys.argv[1]
+        else:
+            self.filename = None
+        self.reset()
+        while True:
+            self.screen.fill((255,255,255))
+            self.clock.tick(self.speed)
+            for event in pygame.event.get():
+                if event.type == QUIT:
+                    sys.exit()
+                elif event.type == KEYDOWN:
+                    key = pygame.key.get_pressed()
+                    if key[K_ESCAPE]:
+                        sys.exit()
+                    elif key[K_i]:
+                        if pygame.key.get_mods() & KMOD_CTRL:
+                            self.ai = not self.ai
+                            self.aiNextPlatformOk = False
+                            self.modeText = "AI " + ('enabled' if self.ai else 'disabled')
+                    elif key[K_d]:
+                        if pygame.key.get_mods() & KMOD_CTRL:
+                            self.aiDebag = not self.aiDebag
+                            self.modeText = "AI debug " + ('enabled' if self.aiDebag else 'disabled')
+                    elif key[K_e]:
+                        if pygame.key.get_mods() & KMOD_CTRL:
+                            self.eternal = not self.eternal
+                            self.eternalFlag = False
+                            self.modeText = "Eternal mode " + ('enabled' if self.eternal else 'disabled')
+                    elif key[K_g]:
+                        if pygame.key.get_mods() & KMOD_CTRL:
+                            self.eternalFlag = not self.eternalFlag
+                            self.eternal = False
+                            self.modeText = "Eternal (flag) mode " + ('enabled' if self.eternalFlag else 'disabled')
+                    elif key[K_f]:
+                        if pygame.key.get_mods() & KMOD_CTRL:
+                            self.playerCarriesFlag = not self.playerCarriesFlag
+                            self.modeText = "Flag " + ('added' if self.playerCarriesFlag else 'removed')
+                    elif key[K_b]:
+                        if pygame.key.get_mods() & KMOD_CTRL:
+                            self.playerWearsBeanie = not self.playerWearsBeanie
+                            self.modeText = "Beanie " + ('added' if self.playerWearsBeanie else 'removed')
+                    elif key[K_SPACE]:
+                        self.modeText = "Wait for it."
+                        self.pause = True
+                    elif key[K_s]:
+                        self.saveGame()
+                        self.modeText = "Saved"
+                    elif key[K_a]:
+                        self.showArrow = not self.showArrow
+                        self.modeText = "Arrow " + ('enabled' if self.showArrow else 'disabled')
+            self.drawGrid()
+            self.drawPlatforms()
+            self.drawAndUpdateItems()
+            self.updatePlayer()
+            self.updatePlatforms()
+            self.screen.blit(self.font.render(str(self.score), -1, (0, 0, 0)), (self.sx // 32, self.sy // 24))
+            for i in range(0, self.sandcastles):
+                self.screen.blit(self.imgFlagRight, (self.sx // 32 + 10 * i, self.sy // 8))
+            if self.modeText != '':
+                self.screen.blit(self.font.render(self.modeText, -1, (0, 0, 0)), (self.sx // 32, self.sy - self.sy // 12))
+            
+            if self.oops:
+                self.showScore()
+                self.reset()
+            pygame.display.flip()
+            
+            if self.pause:
+                self.modeText = "RUN!"
+                while self.waitForIt([K_SPACE, K_s]) == K_s:
+                    self.saveGame()
+                    self.modeText = "Saved"
+                self.pause = False
+
+MolpyUp().run()
index bd18fe44d12a06ceb990973e3e66091883f4f3ef..4e9f59c56d90aa8e0048522c9a8c32623ddf7c57 100644 (file)
@@ -174,7 +174,7 @@ class MolpyUp:
         self.sandcastles = 0
         self.speed = 30
         self.modeText = ''
-        self.playerx = self.sx // 2
+        self.playerx = self.sx // 2 - self.playerHalfWidth
         self.playery = self.sy * 3 // 4
         self.direction = 0
         self.jump = 0
@@ -854,4 +854,4 @@ class MolpyUp:
                     self.modeText = "Saved"
                 self.pause = False
 
-MolpyUp().run()
\ No newline at end of file
+MolpyUp().run()