Update of Ruin by fime ( https://my.numworks.com/python/fime/ruin ).
Added verical wall check that can be enabled/disabled for each level. The last levels are way better on N0120 since they’re full of content.
from math import sqrt,copysign,sin from kandinsky import fill_rect as F,draw_string as D,color as I from ion import keydown as K from time import monotonic as M,sleep as S from random import randint as R,seed as A from micropython import const as C TARG_SPF=C(.022) BG,PL,PTF,NMY,NMY2=C((75,40,40)),C((240,10,10)),C((200,100,100)),C((0,150,255)),C((0,50,200)) P=1 class Entity(): def __init__(it,x,y,w,h,dFunc):it.x,it.y,it.w,it.h=x,y,w,h;it.draw=lambda:dFunc(it) def hitBox(it,it2): if it.x-it2.w<it2.x<it.x+it.w and it.y-it2.h<it2.y<it.y+it.h:return 1 return 0 class Platform(Entity): def __init__(it,x,y,w,h):super().__init__(x,y,w,h,drawPlatform) def hitBox(it,it2): if super().hitBox(it2) and it2.y+it2.h<it.y+5:return 1 return 0 class Movable(Entity): def __init__(it,*arg):super().__init__(*arg);it.vx,it.vy,it.grounded=0,0,0 def setVel(it,vx,vy):it.vx,it.vy=vx,vy def addVel(it,vx,vy):it.vy+=vy;it.vx+=vx def applyPhysics(it): if it.grounded: it2=it.grounded;it.vy=0 if it.x>it2.x+it2.w or it2.x>it.x+it.w:it.grounded=0 else: if it==player and ghost[1]and it.vy<0 and it.touchWall(it.vy,0):it.vy=0 else:it.addVel(0,.2);it.y+=min(it.vy,4) if it==player and ghost[0]and it.touchWall(it.vx,1):it.vx=-(it.vx<0)/9999 it.vx/=1.3;it.x+=it.vx;it.x=max(min(it.x,320-it.w),0) def onPlatform(it,plat): if plat.hitBox(it)and not it.grounded and it.vy>0:it.grounded=plat;it.vy,it.y=0,plat.y-it.h def jump(it):it.vy,it.grounded=-4.3,0 def touchWall(it,vxy,xOrY): for plat in platforms: if xOrY: if it.x+vxy-plat.w<plat.x<it.x+vxy+it.w and it.y-plat.h<plat.y<it.y+it.h:return 1 else: if it.x-plat.w<plat.x<it.x+it.w and it.y+vxy-plat.h<plat.y<it.y+vxy+it.h:return 1 class Enemy(Movable): def __init__(it,*arg):super().__init__(*list(arg)+[drawEnemy]) def applyPhysics(it): if it.grounded: it2=it.grounded if it2.w>20: if it.x<it2.x+it.w:it.vx+=.05 elif it.x>it2.x+it2.w-it.w*2:it.vx-=.05 elif it.vx==0:it.vx=1 super().applyPhysics();it.vx*=1.3 class Bullet(Movable): def __init__(it,it2):super().__init__(it2.x+it2.w/2,it2.y+it2.h/2,3,3,drawBullet);it.setVel(copysign(3,it2.vx)+it2.vx,it2.vy-1) def applyPhysics(it):it.addVel(0,.2);it.x+=it.vx;it.y+=it.vy def fade(col1,col2,n):return tuple([i1*(1-n)+i2*n for i1,i2 in zip(I(col1),I(col2))]) def shadow(it): for i in range(1,6):F(int(it.x-i*2),int(it.y+it.h+(i-1)*5),it.w-i,5,fade("k",BG,i/6)) def baseEntity(it,col): F(int(it.x+2),int(it.y),it.w-2,it.h,col) if P:F(int(it.x),int(it.y),2,it.h,"k") def drawPlayer(it): baseEntity(it,PL);F(int(it.x+it.w/2),int(it.y+7),2,3,"k") for i in(3,it.h-3):F(int(it.x+i+it.vx/4),int(it.y+2),2,2,"k") def drawEnemy(it): baseEntity(it,NMY);F(int(it.x+2),int(it.y+it.h/2),it.w-2,it.h//2,NMY2) for i in(3,it.h-3):F(int(it.x+i),int(it.y+it.h/2-2),2,5,"k") def hideEntity(it):F(int(it.x),int(it.y),int(it.w),int(it.h),BG) def drawPlatform(it): baseEntity(it,PTF) if P:shadow(it) def drawDoor(it): F(int(it.x),int(it.y),it.w,it.h,"k") for i in range(1,5):F(int(it.x+1),int(it.y+it.h-i*2),int(it.w/2-i*2+3),1,fade(PTF,"k",i/6)) def drawBullet(it):F(int(it.x),int(it.y),it.w,it.h,PTF) def createDoor(l1):x,y,w,h=l1;x,y,w,h=x+w//2-7.5,y-15,15,15;return Entity(x,y,w,h,drawDoor) def createPlayer(l1):x,y,w,h=l1;y,w,h=y-10,10,10;return Movable(x,y,w,h,drawPlayer) def createEnemy(l1,id):x,y,w,h=l1;x,y,w,h=x+10*id,y-10,10,10;return Enemy(x,y,w,h) def unpackPlatforms(n,type): global ghost;string=levels(type)[n];Hex2Int=lambda n:int("0x"+n);level,ghost=[],[int(string[0]),int(string[1])] for i in range(2,len(string),9): ptf_str=string[i:i+9];plat=[] for j in range(0,8,2):plat+=[Hex2Int(ptf_str[j:j+2])*5] plat.append(int(ptf_str[-1]));level.append(plat) return level def loadLevel(lvl,type): file=unpackPlatforms(lvl,type);platforms,enemies=[],[] for i in file: platforms+=[Platform(*i[0:4])] if i[4]:enemies+=[createEnemy(i[0:4],j)for j in range(i[4])] player,door=createPlayer(file[0][0:4]),createDoor(file[-1][:4]);return [player,platforms,enemies,door] def shortTransition(): for i in range(30):F(0,0,320,222,fade(BG,"k",sin(i/30)));S(TARG_SPF/5) class GameEngine(): def __init__(it,lvl_type="original"):it.status,it.lvl_type,it.lvl_nb=0,lvl_type,len(levels(lvl_type));it.lvl,it.total_frame=0,0 def nextLevel(it): global d if it.status==2: game.playTransition(mode=1) if it.lvl==21 and lvtype!="custom"and d==1:game.displayEndMsg(1);d+=1 game.playTransition();it.lvl+=it.lvl_type=="hacked" else:shortTransition() def displayEndMsg(it,bis=0): t=game.total_frame*TARG_SPF;msg=["You finished the ","21 original levels !","","Virtual time: {} min {}s".format(t//60,round(t%60,2))] if it.lvl_type=="custom"or 1-bis:msg=[msg[3]] for i,txt in enumerate(msg):D(txt,160-len(txt)*5,111-(len(msg)//2-i)*20,PTF,BG) if bis: while K(4):0 while 1-K(4):D("Press OK to play the",60,180,PTF,BG);D("8 new levels !",90,200,PTF,BG) def playTransition(it,h=222,mode=0): it.lvl+=1-mode and it.lvl_type!="hacked"and it.status==2 try:l=loadLevel(it.lvl,it.lvl_type) except:return entities,s_init,y=l[1]+[l[3]],20,int(h) if not mode: entities+=[l[0]]+l[2] for entity in entities:entity.y-=y del l while 1: if y<1:break if mode:s=(1-y/h)*s_init+5 else:s=sqrt(y/h)*s_init y=round(y-s,1);S(TARG_SPF*2);F(0,0,320,222,BG) for ent in entities:ent.y+=s;ent.draw() def playLevel(it): global platforms,player,P;F(0,0,320,222,BG);player,platforms,enemies,door=loadLevel(it.lvl,it.lvl_type);frame_nb,shot_frame,bullets,it.status=0,0,[],0 while it.status==0: t=M();player.addVel(K(3)-K(0),.1*(1-K(4))) if frame_nb%10==0:door.draw() frame_nb+=1 for b in bullets: hideEntity(b);b.applyPhysics() if b.y>222:bullets.remove(b) else:b.draw() for movable in enemies+[player]: hideEntity(movable) if movable!=player: if movable.hitBox(player):it.status=1;break for b in bullets: if b.hitBox(movable):movable.addVel(b.vx/3,b.vy/3) if movable.y>222:enemies.remove(movable) if game.lvl_type=="hacked"and movable.grounded and K(30):movable.jump() movable.applyPhysics() for plat in platforms: movable.onPlatform(plat) if(frame_nb+9)%10==0 and movable==player:plat.draw() movable.draw() if frame_nb-shot_frame>10 and K(16):shot_frame=frame_nb;bullets+=[Bullet(player)] if player.grounded: if K(4):player.jump() if player.hitBox(door):it.status=2 if player.y>222:it.status=1 while M()-t<TARG_SPF:0 if K(17): D(" P A U S E D ",95,91,BG,PTF);D("Press [0] to restart level",30,111,BG,PTF);D("Press [shift] to",80,155,BG,PTF);D("enable/disable shadows",50,175,BG,PTF);frame_nb+=10-frame_nb%10 while K(17):0 while(K(17)|K(48)|K(12))^1:0 while K(17)|K(48)|K(12): if K(48):it.status=1 elif K(12):P=1-P F(95,91,130,20,BG);F(30,111,260,20,BG);F(80,155,160,20,BG);F(50,175,220,20,BG) it.total_frame+=frame_nb def levels(lvl_type): if lvl_type!="custom":return("00011606010071632010391606010", "00011606010111606010231606010341606010", "000216060101e1601010331606010", "10102106010160f03130051d0b01005160b01005100b01019211d010", "00042306010161c060100e1410011290f06011350f06010", "0008280601026280a011342102010291b020100f1b0201003140a011190d0201026080a010", "000624060101a28020102b220201031190a01118160a0110a0e020101b070201030070a010", "000527060101927010102a27010103420060112819060110c19060110511010100b09010101a060a013330606010", "000428060100c2001010041c010100c16010102f1e01010391801010301101010260b0601012070a010", "000128060101526010103026010103921010102d1a010101a1501010230e01010310d0a010", "00052506010051e06011051606011050f06011050806011301806010", "000628060101623060110c1e020101719020102b19020103b12020102b0c02010170c02010060906010", "000228060101d28060103122060111d1d020100e1b020100515020100e0f02010240d06011320d06010", "000105040100c05350100823010101a1f060111e1801010341206011280e06010280e06010", "00362706010292006011351a020102f1302010042006011041706011080f010100c0706010", "00032806010242806011342106011251906011081901010021201010090c01010150706011270706010", "00042806010192306011251e06010311a060112514060100316060110a0e01010140806010", "003726060101f2601010042601010081e010101019010102519010102f1006011220b06010", "001a28060102a2306010331b01010251701010141706011051201010100a010101c0606010", "000327060100c20010101619010102119030112d1903011351306010260a060111a0a01010050a06010", "000220060101d1b020113117020111c0f06010", "002f28060101428040110422020100e1b04010271a04011321402010270e040110e0e04011040806010", "110728020101e2301010081e010111e1a010111e1101011081501011080c010111e08010110803010111c00050123800000", "11002b020101725010102a28010103a20010103618010102e11010103a0901010360201010260201010000e0c0120916010a0031601061011601071051601051042001010", "113c29010103c1f000112e26000102e0e00011202400010172800010171201110062401010121c01010021601010370e010703a1804010", "1108270101000270a0130a27050121a00000111a1f01011281705010250f0b011240700010060c00013020000013", "112423060102d2302011362102011361a02011361402011360e020113608020112407020110f070201102140e011081d04010", "112c1f060102a13020d02f28020102a28010111e28030111423010111f1d01011141801011201301011280e01011330e010113b0a010113804010112c04010111c0401011100701011030401011", "11002702010011f000111626010112626010103020010103819010102f1401010380c01010380401010250a010102903010c00e1601011050206010050601060000701010000f010100a0301070090901010", "113b2b01010282718012372b01010322b010102d2b01010292b01010252b010102e21010612e1a010112e14010112e0e010112e09010112e04010110b1802010031201011030c01011020603010") else:return("1101023f2b0",'')#your lvl here #-------------------- lvtype="custo" #"custom" or "hacked" #-------------------- platforms,player,ghost=[],0,[0,0];game=GameEngine(lvtype);game.playTransition();d=1 try: while game.lvl<game.lvl_nb:game.playLevel();game.nextLevel() except KeyboardInterrupt:d=0 if d:game.displayEndMsg()