# SnapPy - A Python re-implementation of Snap! # - Snap! is a product of the University of California at Berkeley, and # they are not responsible for this Python reimplementation. See # http://snap.berkeley.edu/ for the actual Snap! project # Version: November 7, 2014 # Copyright 2014, Stephen R. Tate # Note: This code is provided for the use of the Fall 2014 CSC 100 class on # an experimental basis. It is not complete, and it's actually not even that # well-written. Please do not distribute. If you are not one of my UNCG # students and you are interested in this module, please let me know at # srtate@uncg.edu and I'll update you as I make progress improving this # package. import pygame import math import threading import base64 as b64 import bz2 class ExcStopScript(Exception): def __init__(self): pass class snappy: framerate = 20 frameperiod = 1000.0/framerate size = width, height = 480, 360+33 screen = None running = 0 frameUpdated = threading.Condition() myEvents = [] sp_font = None clock = pygame.time.Clock() use_thread = False stage = None stopScripts = False oversprite = None panes = [] maxx = 0 maxy = 0 threads = [] # only supports vertical stacking of panes for now @staticmethod def add_pane(surface, origin='upperleft'): rect = surface.get_rect() opt = rect.bottomleft if (origin == 'center'): opt = rect.center rect.move_ip((0,snappy.maxy)) snappy.maxy = rect.bottom if rect.width > snappy.maxx: snappy.maxx = rect.width newpane = pane(rect, surface, opt) snappy.panes.append(newpane) return newpane @staticmethod def check_mouse(absmousepos): oversprite = None for pane in snappy.panes: thisover = pane.check_mouse(absmousepos) if thisover != None: oversprite = thisover return oversprite #sec class - secondary variables - all these should go away class pane: def __init__(self, rect, background, origin): self.sprites = pygame.sprite.LayeredUpdates() self.background = background self.rect = rect self.origin = origin self.num_layers = 0 self.worksurface = None self.bgimage = None self.bgcorner = None def set_bgimage(self, imagefile): self.bgimage = pygame.image.load(imagefile) self.bgcorner = (0,0) self.background.blit(self.bgimage, (0,0)) def set_bgshift(self, shift): self.bgcorner = shift self.background.blit(self.bgimage, (0,0), pygame.Rect(shift, self.rect.size)) def add_sprite(self, sprite): sprite.layer = self.num_layers self.num_layers += 1 self.sprites.add(sprite, layer=sprite.layer) sprite.pane = self def render(self, surface): self.worksurface = pygame.Surface(self.rect.size) self.worksurface.blit(self.background, (0,0)) self.sprites.update() self.sprites.draw(self.worksurface) surface.blit(self.worksurface, self.rect) def check_mouse(self, absmousepos): oversprite = None if self.rect.collidepoint(absmousepos): mousepos = (absmousepos[0]-self.rect.x,absmousepos[1]-self.rect.y) intersect = self.sprites.get_sprites_at(mousepos) for sp in reversed(intersect): relpt = (mousepos[0]-sp.rect.x,mousepos[1]-sp.rect.y) if sp.mask.get_at(relpt) == 1: oversprite = sp break return oversprite def setcostume0(s): s.switchToCostume(0) def setcostume1(s): s.switchToCostume(1) def clickedon(s): if s == snappy.green_flag: snappy.stopScripts = False snappy.myEvents.append('s-greenFlag') if s == snappy.stop_sign: snappy.stopScripts = True def init(): pygame.init() pygame.key.set_repeat(200,100) topbar_bg = pygame.Surface((480,33)) topbar_bg.fill((149,154,159)) pygame.draw.line(topbar_bg, (110, 114,118), (0,25), (479,25)) pygame.draw.line(topbar_bg, (182,185,186), (0,26), (479,26)) pygame.draw.line(topbar_bg, (207,209,212), (0,27), (479,27)) pygame.draw.line(topbar_bg, (169,172,175), (0,28), (479,28)) pygame.draw.line(topbar_bg, (133,135,137), (0,29), (479,29)) pygame.draw.line(topbar_bg, (125,125,126), (0,30), (479,30)) pygame.draw.line(topbar_bg, (189,189,190), (0,31), (479,31)) pygame.draw.line(topbar_bg, (238,238,239), (0,32), (479,32)) topbar_pane = snappy.add_pane(topbar_bg) snappy.green_flag = BasicSprite((404,20), CostumeBuiltIn('flagoff'), topbar_pane) snappy.green_flag.loadCostume(CostumeBuiltIn('flagon')) snappy.green_flag.onmouseenter = lambda : setcostume1(snappy.green_flag) snappy.green_flag.onmouseleave = lambda : setcostume0(snappy.green_flag) snappy.green_flag.onmouseclick = lambda : clickedon(snappy.green_flag) pause_sprite = BasicSprite((428,20), CostumeBuiltIn('pauseoff'), topbar_pane) snappy.stop_sign = BasicSprite((450,20), CostumeBuiltIn('stopoff'), topbar_pane) snappy.stop_sign.loadCostume(CostumeBuiltIn('stopon')) snappy.stop_sign.onmouseenter = lambda : setcostume1(snappy.stop_sign) snappy.stop_sign.onmouseleave = lambda : setcostume0(snappy.stop_sign) snappy.stop_sign.onmouseclick = lambda : clickedon(snappy.stop_sign) stage_bg = pygame.Surface((480, 360)) stage_bg.fill((255,255,255)) stage_pane = snappy.add_pane(stage_bg, origin='center') snappy.stage = stage_pane snappy.screen = pygame.display.set_mode((snappy.maxx,snappy.maxy), pygame.DOUBLEBUF) snappy.sp_font = pygame.font.Font(None, 20) def breakLines(text): lines = [] words = text.split(' ') currline = "" _std_arrow = '''QlpoOTFBWSZTWQwQBbAAVQN////////////////////////////////7/+q1wkA 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''' _std_alonzo = '''QlpoOTFBWSZTWal7NiYAAD3//+RmRkZmRmJmdnJGdkYERGREREAABARE RAQFBABAgEBI4AZ8+MBGACVAAEQMRTUxJpoyZMmaJ6IaAAaPUNNMmI9TQ5gTE0GEyZMmRhME0 0yMTAEMBzAmJoMJkyZMjCYJppkYmAIYBJ6pVVMjBDAAmmTAAAACMQ0yHMCYmgwmTJkyMJgmmm RiYAhgCkqVNTEYEBowjTTIBpgEZAyGCfvrX75rG0axbFRRtEpIEv17qZKfwrdyjRttdSrWikc Y2ol6oCkx9tVEsO7VRLF7xJ1sgW1QdfA7elfxnUxz9P9w+7HY1O1n6ZO3vwy6OTolIDPM2pAg XkBMicyIJkRCRJAE6j42wwocE3EADOioMIIzoCWDG6hdR842I2drA7Fs1zOOi6dWmIadDEHKq Mu34rwrKCFtTYGyZb8UjQfsYTfjWs3G4wTsagTohkI6GNVb9mo+VGbRS5EvLI/WNFLkVkKyA4 d6xnswuIV7FWLggbSPiiJFVW5BgI6Zk59GRyOpFfT/tLAilc9IpcE0Ie6uomryMB02b154hhQ OrUwMVzG9ta1rQmjxvWxMJ9jd6kWFACVSoWUCXRxImXa19jIc/HGe/nc0+PdTdzdHQ5mqdX5e KPb9XAPBlXt0pzcSObFaApNYq2jZDatp7lSuBM9ya1lbVb58sYEik0aKLUGNGKI0NiGqzTWk1 CMsTJkYBEDWxDRIBRFAIaFksbBQUlSEKKKIWGyVFLSsYTurgYpLRrJtc1y3K5blyuVubRpJ11 MpKddbJLrtFumQxaiQlILVEBimVsRtFopEECLSU0tZNGNjaKyVJbRUFtiQ22TZI2FHJVVFyar aIrZKJtCbJUJyOTUayZos2kpo0lbwEUIxpOCrjbIG0FsjMNom1FoNtottFbURtFtY1tjbSVbR tJtFqI2sRtFVGtjWxq1JG0aLGma0hpNFFjVGqio2rRQm0GjWo2iqKgqIqKjWI2qLWQ2zKi2kI NCVZZVG2rpq502tyLm25zWuaNrm12RaI0VVzWru7VzG2kqySbEQbFrZObctqS0WjFFbFbY1M2 owVVk1GxtFRRWma2jRWixYo2xGNrSVZDYKitYqo1io2xbaYyriRc2yVbcqubazrq1ua1RrcNr msbBslXDKnGkVbJRsFbKSbFWy2lNiLZtRGyVbGybVspmSW1E2RYNG1mmZbSCbaZrRjbJRaNJa JNTNJY2CJf/F3JFOFCQqXs2JgA==''' _std_dragon1a = '''QlpoOTFBWSZTWddzd/QAgdf8tuYiIiACgAAgAIgAgAgAQABAAEAAIA DgDR758KbMwNZWQAC0mZJACkogAAFAxQNNDIyYhQNNDIyYhQNNDIyYgk9UpSA9EABSVJNPUNA PUBU1KU1DQBof1UGwNqramxTY2pmqagpttQymorNWCs1MUEmeWG6JbUrZTKbbFWS1owW2K2Mb W0W0mtRsRY22ZVFqNotWNGtBbGtk1qEsWqCxbUFWNotiqNsaqNWNhWCti0xqoKNWbKrWo0YlL Yq1G2IraNixbFbFsRVGNrY1RrNSbSNlbVVtU1qTabBVqFArDKNTZTFFYK2zVsokFKpWCjKxYt GLbEaiTUYraItjWg1o0bUWKo2tGqAbJNpI2U2NopmlTZUbVNipsVS2qTYQtiltEm1DamybUtk bE2VtVbKNqrak2lS2iGylVtVDagzCGwtqpso2i2ipsqxqG0mxG0ysoymLWophaNsbVKbS2UbC bEZhW1Us222TY2xtJUxNoqSpDbGjRsbbSVFjYqIlm1JDYTwpIHhSQOLtNoti1ixtRaCjWNUTK rZktQytmVjPU62ahnTHRRsk2plbKwoxK0asW1GDbFqNGiqxVjFqgNsEWNfd0xSba+jc3OWzLY rWi0FQV6a5GxUlkosmyXrrjWxbbRRJtjFSWLUUm1JiKYlGTZLLIgzEEwgmksVittFrGtYtBa9 srmSg0YKNRpmSjGsCKGylSRqAtRaMVBYo0mIU2E2LE02to1RaqNGhCqNtiZVksaixpLYrJYqN o2k1g1GLGrFsbY21JqLRgqjbbXpbadbGoVLMJbKPE1Ye1tqubV56HlpzkTnKR3ytjnTjHtPVW 8mdZ6gPPObo2b1bKFbybrA26eWK22N5bFYfaDpCPylAuinalAv2lAsU6KfyEcUoiOvtXWraxr kly3Nc2uVFq5w1GszGsVYrRYxjbYqLaG2p07u3WFYViTdYrY62u5t0UXdi5zZWdbVsU2c25Wu aDZ3G0a5tFyoNFuhuEmtcti3LlRrc5TorCsdEsl0N01Z1uttRu7mrXc2lnRnXW13N0KE0VdNc NkNRqyajVy7u2otubkdC1RRjbNNFaNRoosViiwViornNtuc0ak2yJc3NJSVioYUbDpwRBrAYs baCkLdlV1KMGzK0RRrFsao1q5zXLG0c5tzl0rlXIxRbc22uUT/Oy865bG1EUZNJKEDEjFsV0i Q3CisbRjattWFDrbbOmVjrN1TCVG1ctw7rsWMEYLHddsxpq5WuUXOWktubd07lxZRR0Oju7Ka tm1ctIpWqTcW6zHWx5Zt1sOs2tdLWJstYRTaN423ZqNttLYHWwqpGORVtDeRt1nWaqU22oxnU sbPJtsOJqalJmphW21aRSNrTLY1UURtGKNC87m1jSUBqpNtioMaSS2iQtUYsMMa2NjUhiKi2K xRG2Kg2NsJbGotSbFqZUbY0WtEWxqiixaKsWMWK2No2jJYtRbY1Ji2KxiZTNFqTBRQVIWhNi2 NYsYtosWIrY1ixitjUWxWjQlGrG2xkpExrEWSMmtFotiLaNIMQ1GsVjYKgtJRqyEbRqGaoLFY rRteNcNAloiDRrFtJWDWI2DVjWKjWLQlgtGKmaNqIxWk0bVGLUaotorFkqItsaNbFsajRbUUG tGqNrGoqNrSa0Vg2iI2ixrGsVaNtEqjK2FNjrDdNlVgVtZNVGsMttRjGg0WNRUbFS8K0UgWG8 ixYk0loo0pozKmNkYkVCZhKYgBQTIhRpFGxgjQmzICo1BopptEaNiIXttVQj3qiIYTgE76If4 u5IpwoSGu5u/oA''' _std_dragon1b = '''QlpoOTFBWSZTWeMx268Ao9T8t+IiIiACgQUgAIgAgAgAQABAAUAAAA QgAuAOP3l9NTaoEFLAaUzTBbVQAIbNKAVVUqgNBQAABkyCgAADJkFAAAGTIEnqlRQ0GgAAmpU UxGkZGRtICpqVU9IMgAMns2YVmopTbUYk1UZqtiSo1BpK2Nsm2CtqNaxRRaNYxjUVo1hlbas1 GUbasEgUVjaLYrYpsjZTZGsq1lUyTVjKArNlDUasU1UVhTNTZQrGVsythWitFFqNjRaiiMbbV mKbKxW1CjCttWwltRi2xqK0RGtBVRqNsWrMjaLG1YtqKrANqWsm0TYVtI2qNhlZTM1Yymyhit mUYsTao2pWwTaUq1qJsamwK2zUzZpNsKUqsDZKi2i2GxsSqWyW0ibUtiS2htTYhbI2pTaktpN i2BbRawNo2RmkbE2VtFWsVbVTamyK2bUtpFtEtiK2VG0pW0U2AraLYqNpgylKxsVtmyhtTYpm UrNhRsU2FbK2CSm2UEWMoSFG0mzVRWY1K2xqZtlGyhmrKbbbUGkMrDCUmxJmxsK221ibE2S2K bUWyw2oBTZWZTYqgk1bEjVQiajVlElbYxZHdSUndSUnPI3TcVtTZRUWsEVo22mbJbYsa16Lbp jUbY25yqjai1iyaxrFotsbJajaLFaNRbUbaLaii2xaNSY1orRqxZDV6N3u7avC8K1jVixqwaI pE2iTbmq5akNaxURRtRtiqNhBWSCmtZ47s1UzdbNyaxtVFsVFsFY0bUUVJbGLaMbRaCxRgiqL ZiRmoajCTyh1qrZI2kxYrRisUaNMtjWDbFVF5W6ShVMsbKtmaptF3w6ac4i1q3HFRcYqu+ids p03XRc6UrthHVtWGHTbZTPOHLKZ4jHTV5aitp54ngIr6ihe0ULxBP6iJXhU6oiV9IiU1W/mqz bfBSajEBEbGNsW2NjaisFGjGI1SiihSIW2Kio0ZpoNGmGgplqyWqMSkiYsGmWQ2ZWNtG1ZpJs qbVV9wT/BFcVSVNv1s9VlGrbJMoK1b1s7RXMVzbGuW5q5t023KuXNsod3NsoHSWdORLZ1tTbm 3NXNLujs2o2SuRtbmZ11RTTubo25N0FAoXIq5gMmsbdglQadxRWNG0FFJctuXNjXNGIsaxrZK o1o1Fqd0lsbcsVFFtjRTCNtFouc0l01XI2NFuW1y0XTXLXLmqIMYtFQVjUaUotSWxo1BUVcot zXKNc3OaCuUaF3a6mxqNuBQ5ckmFd0a5bu7Q06MiuVRsm1r+rctEMsza0B4YuXd22SS3d2xGo 1c1ubbc225WkwyayW2plFNIoVs3TB1jWlqsoO1VDcVoSwvbts6MO7sNTGrFWpZtWCtts8TDqm 28ZS2xytB4sq1irZNlNotpRxswXLattyGsbFGrFRtitGqNsWhNitFrJaxtslKKGrCttLbUxWF bKGNCbaUrElaNRbG1JtYtioopKMbUUYgoasKFbKo1YtCjSyxRi1jaxY0WxrIVRqig2oi2jUGx YqixsYqTaCxRaEiqKZti2pNgsWoSk0ZS0VEbRsRjVFRotjYktFYMY2xG1FERFRqKo2MbQaQ2N GNSaijRoDbZmjFYsYxQ0mKU0sFK2VWKzRVi2NWKNjbRrG1mRi0LQo1CLGrasK2JaNooyaLGii saiNDUKVitRtRJtilptPFo2jZmpkvNf6hslRisrFbKUEih1jdNQrVsW5XIDAmymsytFrlulJj RRKYGy0olipI3Q6bKZTVmlmlQCxsWrRtqk1r2W8QKSC2kSImUeV0IlJrLKMqSy0RlaRtMjUoB FpME3mq3lVrEUbRUVqixqSNixtRsJWIo0CRgrJEbEYoYmg2ixgkNEUUVGSSojY0bGosai0iGi xFZDYxrEvbtWqiekSCmR5U5bOvHGmtrWaktFTSzDUaEqEilzojaklEZooqMBais2KWbTCs0a2 /4u5IpwoSHGY7deA''' _std_flagoff = '''QlpoOTFBWSZTWZqpqYcAAU/EKNAAAQACEIAIAACwALhiGBAz1UNAQqT anpiihqouqiz8QEsVSRFUSSNJRgIBwUOQ1BMTNSlJQNLQhQUlKxBfqKGqKGqi4MDSNKhShBAl EWhEEWACS34u5IpwoSE1U1MO''' _std_flagon = '''QlpoOTFBWSZTWRegx08AAU/EIMAAAQACEIAAsAC1bCT1UmQQqMBU1UY xRQ1AV8QEsVSRFUSSM0X1aq5bVxYUyZhtGiGloQoKSlYgsUUNUUMHjbUZW2xTbIsFBNqohNAC tvxdyRThQkBegx08''' _std_pauseoff = '''QlpoOTFBWSZTWUy5/dEAAPrAJMABAhCQAAAAoABwQwAUlIaeqsh1Uy i5VGKOiWB40tLZWg30pdlLgl4jqWBwS4qOJfi7kinChIJlz+6I''' _std_stopoff = '''QlpoOTFBWSZTWW4D0+wAAStEJMAACwACEICAAACgAHBBkxAUlKaNqex U9KuRU8KfSnHaWjLRmDMWYZjXpV0q5FTqeVajVFmFmJmDNWr+LuSKcKEg3Aen2A==''' _std_stopon = '''QlpoOTFBWSZTWV2XKzgAAStFIsAACwAIAAIQgAIAAKAAcEAMApKp6hp6 nhVwp7KcdpaMuxU8ipyOMGYswzGvxV0q9RU6nyrUaoswsxMwZq1fxdyRThQkF2XKzgA=''' _std_carcow = ''''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''' _std_car2 = '''QlpoOTFBWSZTWTeBcCkAYYjwMOIiICIigAAhBAAEAOAIHPT7RRZamI2yIq bGBKmzaKYACaFMABNCmAAmgk9VFIBpoE1KSmmgwBU1KpkAD+2t6lsJsamBGSSSTTJgBBmNEpW YrStYY1VpJVkhKwucWsso2AxshoopYZNoqyQ3oWxsyoqI2KLX8zphyG6w53albNLBs2YVTgdR 1ki2k2pLYlsa0Yyg2Vs2o0gK2GkCWalZlYyTBTNisrMzUAVmxRsymxstVDaqbAm1VNpLYQ1Zt TFagorSM1GpWGVtim1DasCtttRTMrMSZqYVjUNqNq2NTZYFtJbSq2JbSqK2KIo2o2xqNYqi2N RY2jY1ii0UYjKsqt62trCz0RBaS61KrZsGttJsqttlYorbFZWCsFKrY2qtlbLZTMobI2RimxQ zK1bbFDKDK2rCpMymNWxRitWSoyVFW0VfM5+c6d3HPvnjxtcagDRGmCEa2zNW8+uVVdz28u92 Xb47t2X74453qW9lbjUJjZLQRmVtqrNvi9uc82bN4tRimxTagU2bfszHWGzHrbYNHtrz3d6db 3d28dcet4las1UVX33WxbJbRWwm0Ntsto2oqxsWsUaqNti2Sq2KyWKGSbKxWaWJZklChtVYKz VsKCLWk2oyGjYrRtYtFUysGrG0Wg0mKxGo2xa0EY1Qaxti20kFVtVbKBRijZJRnQ6zHXSsKZi gUVaYoFbbKUUVtlo5OlJGBaxtqS2jZMVFsYSE3ZDpEWsK2E0K2arGmYIDAbARqirFtMnG5YTV zTW5QExYsrBNqW0NibTZG2sjI0ihuRjpkqtJVLbY0sLRsOMrbVgkK21MrFNq2pWrSLWNjczYc bWA2kwkbRFSbFNSJbAk1GKxIoSUzbGCNGgsRtFYtsRRUWgkoEtbm22ba4o0lti1RbJsWqKgsb WxajY2rCGmRVtJpspWUzZWNW2ZWCmzagrMKU0sZTNWVmKYUbGsSWttMtiNUVszbGiswVlCm2y m2ajZTNjaNFrRrNNWErJqKmGsmwVFoti0bBFozYtm1Ntotom0mwthGm0qyhq1UKxcMYN2DrZq MVtqFZIFatsUsa0UasVtFtYto2i0UtbXKRyhULFPdVLqkd0yNmlKTIbX+LuSKcKEgbwLgUg=''' _std_carbug ='''QlpoOTFBWSZTWUm568YAAEb//+//7/7///9/fv////7//////3/f//9// 3//3//fb//s4CY8+D6AKxAikKEVVIiAAU2ygUUKUCbDbUxbnvvmZUAAA6IkChmZtHO7mZrdru I2621Otp3du1xau7bMl3VurVtuMkUuzQgozpMIp+iETEyAaAJgTRgmmSYEyYTCTRgmQnppNpN NPU0B6pgMhGaaJgIwTTBBgQehBgExo0nqMTEwAJmo9I9EwNU/QgEAgE0NAFPTSeQ1GmlN6mo2 aU/VM2qDTT1NPKNB6gNG1BoAAAAAAAAADQAANAAADQAAGmgaYkQQTRoJqeE1TxqT9Q8UxJ6j0 2lHlGQDT0mgaAAAAAAAAAAAAaAAAAA0AAAAAAAAk0okRNCNGpvRNTE9RsoANGQMmmnqAAAAAA AAA0NBoAAANAAAAAAAAAaAAAAAEkoqNqenpT1A0AAAAaGgAAAAAGQNAxAAAAABoADQAAAAAAN BoDQDQAAGgBSVJEyKeSnppmoelPSaPSbU00YNDQR6nqam02o01PFNHqGTyRhNHqaPU2iehB6j JoZDxQzQg0HoIemoeo0PQ9TIAZAj0jCemptCaYR5P/Qn/UBZFgqixEBYiLK1UWLIjWsUEViIi MRiqKxRzb6jHGlsnKlVYrdMVWT1xypLpwHtM+00Jz65oqtTiyR+VhPuNL2+o/5YPv9OnRO6KL OydrbNta03aLu5HXXPKv8ultJ0FFi8dTUvocvhZOtKeQpTp4lOQvuMKAhA6kJDgkuUyHmEKKv TgJB42SQ/VFQicE+0d9Inl1Tnc1XscQeWRH+yuPOROfy89A2tGxNZtM2rXNXuNFd9lLn79EeB U4NU5VOukaV+vqckjU9zlF4ETVHU6K3oEV52j0cudQ5vBRXFQ49J4Rm2ytkZtmiPS1XJ6dTyt x1CPRqHD0VRySPmar6dPSp4ah84odHUquwkedXCekyXld89UaHqsT/tgvUZ6jPI4+f0Xg5Hgb rYct5vK+kldvw7RD1OWfwlOb51BDwhDiiULXoThqlEiBEKJU5gFFMkCdSjr5m11OST+PFMovP eDxLm56j1iqeEPGHFVbalQKyKAKKRkZKxQiNottYFgJSLBiJasYxKWIqIlWW2nOyGuB316UkJ tsOZZAN+yR/r12PRd7DZRtW45JP5nsdbWZmwxk1tltsz6ZT+e/tkbZ1PF1Dpi4ul4/SeHjlro yHrlXL1Ryi/Qp3MV7JGNV9lpbhPppX2En3M6EPUKtHPV1bWtqbGxtazrcp5bR8nlf0Sj2ipcB OfpVXX9rk2OG42xmm0zCyBVltCoPOE0A5lITmEkA3s8qCqCIRRBEYkRkF3yigXm5CTa8tOO5y VlZWAiALUrKQlYUiQS2VcTJrjOOOPi1Tq1ea0jz2h1Kgw29zSepYHeuB8jn8n1ee99j2aTf8u IACgsIKsWAsIsiiwVVkFiwUFAXZsrZtrRmmzufrxXMqXHfnnLWto2l3q5iT/SU+cI4eHqjxur px/Lq+31TZs1RmK1q1tsbcuJcpPhZQ/yR5QHC+vyPKZUvP4gdjjViJBUSLBRUYqgoCikXNtDY 2WsWy2NrX9pJ5Mr2b21qs21mM2VVm32r+7K9kJye105sZq4xxuMzU2bM7UvFFenyf38pHde0S +6M1Y2N5eoc08XKxe10oGr08kPbMirFkNdKAwqUGqigQFAixjRlRVUGIqsViilloUEtBXGZIS HLnCVigqpJIcRD0srmhTm8ltbazNmb7tQf54+2IE2TVJIQ6/CHvETnbYtRiDS1VY4ccZyqeR0 +8elPOKnKh3aLlT5qPGXt1RVVRUUREiIsYLBYpBwjZbE2NtrwpOx0F9nkjszQhJoTdqxVRiis UVUVWKgosRFRRRFQViqPUwwHPEk2wnjKeQk8WhfGyOvyQ3RSNqd6qcdkTlQX9QTtScSftaK5z Tx3tk8Kkc3NE7+v92S2bZRbh9rjn08dorYYE4PEWMDodosHffCbgCmLyCZQc4wGFYI4GpJc6X GXSyOAuAXTACjA00yYmWIxspll0cuBzMOFUdN5A1yEk9zIPPql8oqd+SvTVDuZD29XQu61EfH J7d+U5v+pG/4L72y2aVN5t11Lm6temLqMk1tkwbE2zTsS56hc/mEvl4XQF73SD8K8pK8CkvvJ XNBd75zPvtxw3G42TZQ2jXbhPOy6JHnp15XSDuO9ZtmZsa0m1tstrY4q0LJO31J6z6NmG0bNt lttZ3cL1de6xgbeKV2MG0ahzz78i8xEOqH2GHq9E+SxOxpU6niaTZbVZs1W02zG1Nq2TatazN pcvc0L4yfKJ29R0Kh0RT3KI+9HKT+m6vEeaweYlyd3VyjS6JXn6HaXMlXz6i+KUHYpyqvTB5L 3jamwzLWRsWY2pmKAxgKswTeiEkOmTk1ioxWCOrNlbWrbTdt8gXSnqa6iS6sU83COdFyld8r3 Z4Bts225Tsl2UcFH4zAuiDKMk4w7kKZXUDDDAQUCIVCUvHkpFhQtKMKJJCXZ79rIBPEkJgAJ2 j7CcijOMONHC2ra1rxx4lPeT2C6Ip1+/eDmzjbNNNBtUzDcOhzBHS4M3IVVYqVikkBQhUIqnR 4EJzSd2dThbV52Qe9H5mFtLYtpbU2Tam2zZbxEPl456vmfluKhfwIHVvkAcp6lL56C+RC5T1t Z8rpB6K7bWo2ivLIcqfcpq8elq+7yn5A7Zwr6XU9Zoj18qdCvSTwl+fbQefI/IPJ06VQ988Ns 09+zLWm0443bfn+LYoqsVFYqgoqQWKxiu9CL+KlXSR+hz5ts1jWZtqzKcJPX6l0beZk8xFOS+ y3tkusO8PCJzIfN/o6bLaZlsmba1g2m1woB1Cc+xHJRCsKwWCohUi1UvDjdfoUX++LqB83ryg L8tcK9/Rl7rU9xnVd5DeRTlOzl3hNfO0d5FOJ7Deh1J7j9PbGbSzQ2Mzatmta229UPriLmkfB /SxdmpXxYjq879XPd5VtH7eExiIMbZVRUYoERBiIjyPutf/8V63VHoydqHj+V4+rxOC9fJ25V cF8K902Wm2w2a2bGzZmYERVXXwZCcpCaQIG8NBBVREVhrbGbTY1q2t1qpclJ5np1dxmVmXGtH GHsvZ+VgdfoK+B8DNT4M/Tq5o8Ii9dTplHJV41D0CuEOx3G2ZbZYZbM2a3c0cqh8J7NrfuHFw 2ZxxtUcf0CPDl7oPmi7npJ+4l6G+Rf/Y2RnYR6snUnxSP1UnwanJ77JeK0DhoSBvQ4G7eLVHE qXFbCksrcYBSYkQC6tDgG4RQVUUikYsBFETMmYcSA6LIj0FpQoShiREIlQSLc+Nzx3ESl/V5O R4U8OOz8x0CndO9s22bBsM2dpS7N9aV+xczGzOoDu++a0bVHE7OuzRfSi/LLS7ycyL/8S/YLw aftT916Q02/m1H8ZD09TqI6oHxOp1v3muXHLXAUaMBymMErBQWObVYLAxgygmNGSSJUB1JTRS yAkk8IREICoonr5eZgEvhyjp6Q7oj94HajqSjuJXWpcfGsI/gD5GuB1CUIhIaAwnrXBdfwYYY ZhmhhC6yvGLzyL090ynfRnbFTtynw3KfqaI80+GS8aS5PIOrKPiLkDuMJ3W7Od1uGEAyQhy4S hAManU75X9yA2wFw5GA7FwmUywcWsPDM/Yn6bVhlNbqYe3SQ0YTRFnNOt0ZMofoSFSLIKC/wa js6f7c/74dbHNrrY/8fJVeSleVlPDO8GZmGZJmBMyQzAMyQmZTs5A/k/lw8tsas+w99lJHNy3 Wp7Hg7an43EnjddPF6/U73ufbfKl+78ITfpc6Y78b0M7w/FSV4vqfrN9xF67reH47z3zP7lr9 l/LKa8f/674//S8yJ8ltdr3X2hwQ+FZLSOQaENXyID8YkNgWC0fFPOkSvu9Zc2zywKgJf8f7I MCSas2YWD+1f6IQHjZEqHX1iinoSpTh6FQzTf/x+YMlBmVqRDEpYyjws7mfDpSIx0x7OOv7bM BkmUBXj+TplyqqFSFTm/v8tgyxNvf7fH7zfbe3szZRRXi7qQrNblmwlEhxjNaOLrQ4rOVCFCA hA3dKMWQncq4hNaaYVB4qDCh1uTU+NrxTAjExk+9WEiCmJyrIhQdBQ1SyhUNVlIMwDyKiYNUr 0kvnWZMimMRsuBUBWtsECwhwWQEkBX3iVaUkAhaRYgmJC2MaHuaQjGO1hko7zRIvokSwJAzgD O++QQ2bt6YM6YQmZ0vl7FqqlIoapsRNxAocZROTfYWJk51rdN0yHEoIFDGECuh2uLnc43OPiS n599y1WIqLiFoLK3qSDqIeUklTjVWUOpaJ+9GvchaXyTPY6+7GE4jNDgpPdvQWzm0XL2w2Ofs 8G/Tiu7FAGI4Jqu8tdmN6P3t0PXMzKRFwbWi7WZRn0oKyIB3HTCb3g3adkKUeoVAiwrapwrcp eLFm6koQKooZpSDRZNxLwz4IxDwiQQEGKTm7nZyKkkTj4P+eTxtO+VsExxkVSFBtnQLbRHaVQ MBxMtWdxTaehGwZrZ7d9JNaZgoJ00qHC39TxbXOFBNFmQUQBkJDLagQGvBbHptm0tMI7WQ5Fr VGc9FcHJRaCFcnylVIhFToM8M6vz+FHV0v0b1183LG6oh18X8jnm4ihGOswGJDSIsztvGHXCa 4Cu9gXishE0cqtXbCAbeyooy1yDFoBhznWz8j3AGGYGw+xO5b08VY12DA2CgOXfuwy8JD9a9f wouptHKDsbfW9gXPXi1RvO4cinBOHIg1Ofb2KftbJ7XDjjy6ul+ngSVe2txWe7XVnzffLEa5B f+5K7TTBndja1RHIVtQQhWy0xemt09y2N8xXoN+5owfSurqa+7pteQ6GFyLNJB9sNWV2KRcOp nKhINqoBLMknuRkXVUE1017adaiVaZpSVeTgi2acZPu+ojEr2KeZomIZ7bbqOXKU5pblrFzaF CoaFI9O6OzPNZourC1phY/J2GcEkFZghkqFWwYcrIHbmTYqNbY2eaRuRX9mUbLLYJbvbG/w4u bEXZRiUt0g1W17VVuPNY+5NW3mNBrhrWnjNlz82oaDggSOtJqy9BREJxdJzB42xFFwith2yqn VLcZ0eayFIw47suu4U5f2U6e3m7ktzJC7a9Wme3VTHPOmhToJsYO18vaZdYqcmm7m3QgNquGo hOhckV5GfksIRQPXblGTa6/Bhdfuv3+Tlmod46w3bE4fK1WaHPEW1VyL1S9n54I525CTpbaV+ ZKvCNAycViLxGaWIllPDbw7t+VE5r4x0iFtaSP6Wn+n9PGcDDOns4JgQ25ZZLQs4QXnrg8PqI OW5BLRB3czV9W/SU+ijnSchLzgVKEWlZwJRhbSAX9p37+CDbvRnaVOrcu6S29QRZ9HWUbBTqm lMc9iyBWFGkyuqxEbCY28nHTfVHk63IZXnyo7+ZHMs+5uPo65oXL7JJLadN2LTpsqyUUxMsWl WdewR8unBDalQRopNnGdc+kxne4a70CG1HGzY57WuTO4aC9508Hi5XwhAc/swlvDTkyOjPdWf tfCqEbDUF7SDazJUFJIUGXQvBb1+0nNOUblM8L2r0Z/KcW3OpYV2qbMbi4JC7J6ARZANHUTHX p+wUxy7HgevvtyB7p2Q3OluZF28eCjfXxtq/zvXFHl/LkzKVaaw8SygOQpFLRxYgWrBhQngW3 iMkABAANa4QsZkeJmHYo6Dv4hNmzNOZo0F9ia1kbCNsTylOM1HGV9WwPAwX5L4a9ik/mhlhWH wLNmLlR7Pclbs7HdKh3+Ppap5K2cEqzZCtWab9ueSHqayT9A+XXN02iPoUUABQLfUaGFO6FTC 2+6pNGAHidrqz8+CTNVgl3JhmSDosm0KLLQdpb9GOjsPB3/Yd1nvmmEF7fBpR3gMr4W53Cth5 GxyuyrZWyaVaWo+08Tyo6xMt2TsYzxIqYidJdyeVd4rutKvs7rl9HhoE25npaUVq2dCthS2EB DL8F5WC5Q3IV1XZ2DmR3mw4jeJ/JLlZ0v69t51VBcFy4/OBtNAzIwRADWLBrrexFk8SlSkzty Vuj3AOc/xOTYqG0Iz9C2aN5hXm3/aP2+PDMkJJcOpQolPQ6pIrRPReZoNY8tpeVjc9S4Wk7S/ Lsa9Xgcvc1Yv4V26RNOEtu/Y1hq7h1wWdiWCQdCU0QKGJEoWCVNVKq4kyEgyjFWnuHTrMVkEI IttpEQoVV4RfT7Q4+mut+55e9xnVw+DliMZwfgHAlxCjBArK4uZg6ouIXFkDkPFBC9fdJLjG/ JqjQlckFjZImsjESS+q/jsYQ42+6olpJFs0c5KSGPOzSHTp3E+OCmThgioRrkMHiG3kOLfgGT h84WBDnbuHkrE7dyGZXrPR5S47sO4qjLkJlGRStXdv7bsZLrTyGFActpxBMQmm1wGUSuPk42Y H2C3f9+2fXQG7rlwtVxT5OlO2uGQ5C4kqoK5S8hDUrj4fWjB1pD7Lm1u30PRlcqxtEkJGwsYS XuzcDSkUaZggJtGEYGAo6VN7izxeDyeTjw5t4ZMWzjopop6rNaY6osGG2CXVosIGEV1/JeaCi HGQcGLSrL2xnob2LohlxqcuIlaLt7NwizLKu3YaY2caRUFILDVv6SaxhlLNXAxJjp/J46RksW KsjbBuECaL/gKjxIUInf/mQOUU2XXn4tfjVNLJvaKjtd2kbDVQ0FSEURLU8U+ro/x5STpQzfy TmFF8JbtI9X1OnRTkj40eVW3eDh4nCkaZA5sgl4bBZNIMEJwttMzNUgWoQKSCIIIlIkkzOybe G/vVq6nA8GztN8TFcMVGwSEWEQrrj0AHL3OA996Pe5tmfdy23HKhZ3OcO5xXn1dkZbWwbzjcK lNPiMy/bE8X7rzmpi5So3m/L0ZHDOz61KwREGg0M0FtZyKUJ0tpReE7lxViXRV7NHeZOZ6vJB bw1ZzlIM88lk58JFeuiPnAIKOi8owQ9CKspo9kIBaJFi1TVHQRbLej+bJznqO8YueprkAb7dp z8jTMAcAyQc/QyjRgjRMaTKRbRRKEkEk2evX3x8+3tXLxu4PD7vNi6KBQVjJhz8MoclIQBO+u ivZSjPDkwokOuoDjKOiTO6VpookXcE5TrGIgQjGyAwCDzVMooOLrw8PBhFAzkGwxt7JpsuqQc yICag8wVYF7M16WS5803Yn0aDH2mRYJymBUIN1QqKjyrVVkHU0WFGiSoHGJhhmJIHN2SwCRnW ZbZodAEWNASQbkzlVcttlY9/wObF6mMT7T992AKEIJaNQJTcf0LauFt2tCLMwwGlgo4aMwvhp czoWF3lzMyacL6IcaeDJGlmDAhBQSlHo7fHlXy7fXxTOd1saRqRlZGMLpchSrVGE9PjI+W484 HLfM7DMq0mVtPQ5BFjxjZ9z5zy+3q8fchmN7ncmTX220Us/e0Bm1YNvnSnW0W6qEIgUCQqXQi 6gspJdRepJgUMAcUxE1rUNBB71w4c34L+j6zl6nBbyFiY1M1sykSc0jNMlEIwWJTgsZWMYqwc 1SphB0sJlzSweSq6YqYaMIAEoMlExYhYhIb/Rn7u3s9fZ0b95+jqJle00PjuE2IxG6GuUyPR5 vEFicbpsPSWv0syh3p5u7peYiHpUwpk9hv+Q/Cc+CnqqaZlk+enbWVLv0LhQYuHpU33pJ58es l+CFAhBaEYaBAAlHVzpgws1JUBGVRkrNSTgJMoGGtQYgIQhTvugziA4gEIyMoeXOn1SHl0D5z ikyijIkQAGTYInxxLYBHxG97nP/p1D8k/Ww9S+q0Z2tDhRzf3q3mx7fV48pd96lEQnYy8Tdoq MET1uMuzowfwiWicLssGL7wj3OY11pSul5arwbfgeU8/hVAZ48HZsWzkrbF7CazLQBICALoK0 VaaeEOw4q1+rRZS9oebWNqwtXedZe+CHVcTelTy2RN59BQ+jUYwlEC1byoRkGDIlBDkqJPLqS 4otZXyN9n16Tc7EMu+rXp/A6rFdpUpFGyd6ZI0wtV+MtFJZu6r1tyUhw9NXJtvYy5qI1mo60i 0uraXkOYNfBfldyrZwat70oV1PXXca9/qpAF8kUEKCSko7QpXq1XYKbVtJFCEaEmFZLkGBQhG m4giKEEMOZbi6A+W5nLmNIQW6d+b1viZLsiDDzk9yM7T6EoCPnllvHyPvA9u1+LQ/C8Hn8gQP nhoODJbQYF2nIoJIMoBAXIKshmiubQ2PHUMDMqmbKri4cKjBOZxyOzkgGEKh2HIZHZFJBnlzw ehaWWoE5fEy8p2WUzTuR+/bMnzJsXiSeZLDjxuHtk5/K0NYPf+RQwAjYt7vOuTQ0VrsaIJOzR 4d0yNLyVLNjOKg2hhNSTDMJtu0aqTNWwwCwQEuYM3k8HNKMB2YDs28b7AsEj3m70vQvrytMUz 9GyRIFCMLQJEMxQyYFKcNgZ8MJJUFEBJBIXO9Q8MakQFOmT/ivec3WtjqvgtdaEdD0ucUuXBQ 0ZxB1dGIuz3ivZ18gO+zkcx47u+WEue3XdU8q/EahHHajY8rrI8xsFRhQlqg5Lf7sLHqXU0S4 vM6F/OtFs5/3cvlM69eVqPZhVJ9E0jYY05vcNbN/cVFczN/+LssNfSzjIA7t3e+B3FGhFO1y9 3WZat9lTor1XSU+ZLGwNvUHdk9YGEHAs5FjxcpPLL5L03QCPbygPqiI2eszV5aY5IWRc/o3Z1 cs1ZUhRoSgBSkhJmqipM4KSKkEo9VLysoLB9SQZs8Bbm2Tqfb3jMzrsL1osXINZ8m6bFf1M95 wV1Og41uhkWImMIBSNqZZgIHyjUAkBhVVVayta8U6869erRcsoo4c4zgE6vq5ibW9/rPT6cG1 tQqEIaaKQZwHby4JO1z5kGVm6xyXl7XLG4X3VAWB3D20DZyuTsaRFmnzy09au5zBbqgzc0HRh kBqESRrEVB2N1taZ0RERYrLarNSYFtnS2bLmAASsFttdkEihpernMo3arfbntFXr7E5VnjKlu lUCE6G+wD3I50ZyEtKfaKPa4LWrisnWtVzsrbsyH2WlGA0AROQhGgA0gAhJDOcIEgjwEsGpKv 5GzSbm+CX4rqi67Xazvg4suzl08zkdBLOn5rS0y50qjWIoSwqMDRIETKggrUaYJ0DUIQURkYI NIZhoAz3DbJYWcTkS2Ln1Mvg73nYs2vfz+voyym1TIzkmSAq0ubM3urp5nR1upy9kwgBag2pW ohKUhIV27rtjqOc53Q4iR0OHp7WrhwyyNU2PXcTBEkS4AJCo3DIBIqqm5B13CahA56gkai+fU mM4o+DamiLpwNPRLhmgq6IsUxpk3eTDox0pUxQ4LiDm0L3qH1sjFaQIrfSOx+29HymqwOj5hY Po9O9b4jX3fM/PRtzudlmxSxRVew2FTU8Xy1hl2BDTFUDBgtxCITbTZLgENoPp8lKXUNoL183 ydMmPg4MWBon0UcBtGHDn9DFajbe57Ld87ycHHdwknMQ3wojaMidm+im04g1P6bKh0VWNdE3a moHTmki5uTFlWKmUQSCEUUS1c1+9wKgFd3Fmci9aXXgnSenERzYDYZTiREUozE0KQwCMBgvCx AziypIsdlqzTauvMsYoKOd4qVKxsZPMGrhVexwlSVDslodffZhnB/Svf0OMlRWbU+SK7ffzJl OnT3TjldrBUqptFlixGCJS1QRFmmG0QQSYJgmKNIA4ijMIFExZq3a9JyG3pcF+88Tj7F9iRdA ev26OX1mKz0dbqYoaNCS363uV1ltiYdA0a1NNrUBgt8Q03VgcR0SRYoskm7ZDVcPazkuQ65ej cLG53NN4/Bo7+JqDKgESEHaSJqZ4cAoyIy06pzHH4jczoT+1hfByEV1W2RO2gv8DoPxeygIiq EIACm+RitTmpX1kujNzJX501y5ktBvPQrleqkE3ItOhlFhfdjE+h3GwnWW9NeOvwGhRAGYKPp zFSjWtuVRnVQ2DlTI3PKtUm9nX6SqTIqct4G0ATH+wG8lnU3KzuVng1iU+FbpmkFC2cthUQTW g27Zl25b1nlcV64FDvjaCWEyK5EYm8yOKsb1JQp6Tjy7tkgQRIgICCiZMs/O6vodbSp5JzZOP 726By2hE9f2nasiU2mWpqMjt++73ov+Ts8f2FrnYqfkxruWgvlZaesHE1LGp5jnlwD1serzXL VIUtKpHb4dy70rpZQ1czS4WFNo5F9mM+9E/ZdnabgUIoXMh+DSJx8HnYmOEJhsRp4ygDQyHLA K50n42a1fDwHol0kNTUPISQ1wLZMWi813LCE+GTyRbkGQo3khN/gYQlElVfharVEWEBHFKrw+ HDOIEwkWSO9U6EuPU6wu1X4uxjnnf8p5Fq1UVsJKSShl/AntZ1Jls6UaUwEKZXZvYnfsYty3s aDsMsHIBIU0zQEYhMiI5GG+qB71V5qJ9F0rRDz1HMsZAJRFrYqQT2hl4nutQdrN3SzQDUKMQi NFYztznmZ3z7rs67g0W2bhMoamfwZFmLDsIJSpoN/jGuF5smMbXzKteTzIG3eLV5NTj6t/eFY y3XoCkSTzKhUgWaojE/+rNpKK1GMgj5AGKoaNNZKC7xxIV/NpzOvLj+m4+T4DSLxaYKbQdGzH LBszw1Leu2bsd2ee+dL821JqZL4NtXkuc2xctyTAppANjuOnovHfghriS8ZgoVSGf11JXnuVg jr4kXzR0EJjCBsnwLBVUAs7f9pC8WKxunEKGbDF3hkcJFIBAUDMmiMFYEqxKBnmrpYLvd0npt eaClkJhIM1GuYrpx39+WnmuGtysYzal0RxcEuSUoz6zCzIlHWS5mKmUXKF1Mm21XwYixAvMdO 29pa8FLNq1EtpzDS9gE0c68qhn8+lu7r56S7FLfdunCndx4+ONIJNn/Fo5QQrhnVGhBCOhEI5 U9RijYu1Mm6bei217rLUPhTya4PqTSbQ/k7W11CP3S2d+vhwHAcm2iOz6GkcrZIWvqq4aLqL8 zxWSNTO1R0S4Jvsw3akf8M9cbkQg64YqC2VBBmBCpQhZtBck0JD0QvS/BVabm3h79Sdce9ss1 Sqnlm7T8TszYrljJX6FiRr+rgqCmHeNJRpCAWAZGAIhCZmaQ30srrTqC93ZiFgaW+bbfemDxt qG2kCKWUqiqkXoiopueAhmzquzF5VsLBEERcsHqmxU3W8Bxzz79LJ5zGiWI+j2YOeqEmDYMji HKgXMbT4Oslo+sn3PNtrhy87X674LASZW20GxicY5k2TizppgWUjS7J0lJrmG8ZTQiTES0AyE cZbQxFUKlWPaNBKhUQZGjXmG2uYQxZ0XNcKym433KcdNliIqixFEVMm4N3imtzus6YzyO/81U XCIJIMYRZek5NpfTKHKKBzXSZ5bDEgmxItc5iV8vOuVwrAIpNt9I4MyKWUWpITVGGnZg4+fta 5BdjYbhNgUYiAu7tMJpiiw69ajjdXXnUYEGR6A2CoQBiAjIQHVpxuBQq0FU+43t3Cw6U3DAGJ seFCpUhPqHXjLnryxkapwxThro/bKUTzOzQQZHoAhH/4u5IpwoSCTc9eMA=''' _std_carblue = '''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''' _std_bomb = '''QlpoOTFBWSZTWeYf/GkAEav////////////////////v//////////7/v/ +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 DtAL92ZP/xdyRThQkOYf/Gk''' _std_wizardhat = '''QlpoOTFBWSZTWb/rHQQASBRSg8AAAoAACAEAAACEAAAA0AW+PJQeW bW2oIVs0biGBBDAgSeqVMgJqSk0AqalTRp62bb0BtGB01NpNTNlNmSUzU2zUbFFBVYpg1YoU2 ZQbU1bZlWSLZVWxFbVK2Q2UltFWwtki2CtqotpbExW1ZTDK1MZTDJbbFbMUrGyWZqYqtgrMNW lVsjbYmmqNiaxTNhpM2qhW1GyswpsSxlGrNqxlKYSzaTCtWNIalDSbJGSwtGoIsy1pbSZLUrN sLxmDPGYM74KMoFMKCW2TUUbSaQtoxppapKLLAYqNsq1DailstZllaksUyZmlthQ22W0bRRbC lK9gVV9gVVwQi+Un7RbFtFsg2yVgSBlV7RLmsy2u3LtRTHVRqLuHS2Zo6SuSaRaaytrTZjapi VEal1pWym1OxaxXZGsYrMrZyFozoJrVsrbs2tcLSa6bW4bZDJulbrMmu5xztuYotHWx1WYa0b WjVo2oxqK3Nzaism0a5XS6WLbG0aLFkNGto1c5rpblJqCuXNsajQzbctcTbRtuVc1JNC3NXLY 1uwtoqNM0mxIZTKucdbrcRtWalbpW6zOm6Z02rMrMdFG7uZqN0Z1q3Wdbcs6ZLUM6csddNWOt WFMUUZVktcq5EWjUbWNoxaNlOmdu5q262KbFDUN1jtJtLtR4EIurrUbI2bEWq+LRttzUhsaRT RaRLRsUVuW4aLYSMkWNaRGkrNRlbLLbLLTJK2NVGTW2ItRzm2orRbUmwblzWpmiwFtFGTFiyZ gUlmQzDVtqzW2bwh1IJXhDxdyRThQkL/rHQQ=''' _std_costumes = { 'Clock-hand': [ _std_arrow, (200,60), (3,30) ], 'alonzo': [ _std_alonzo, (104,128), None ], 'dragon1-a': [ _std_dragon1a, (133,126), None ], 'dragon1-b': [ _std_dragon1b, (180,117), None ], 'car2': [ _std_car2, (180,72), None ], 'car-blue': [ _std_carblue, (200,89), None ], 'car-bug': [ _std_carbug, (200,78), None ], 'car-cow': [ _std_carcow, (200,62), None ], 'bomb': [ _std_bomb, (48,48), None ], 'wizardhat': [ _std_wizardhat, (73,127), None ], 'flagoff': [ _std_flagoff, (20,17), None ], 'flagon': [ _std_flagon, (20,17), None ], 'pauseoff': [ _std_pauseoff, (17,17), None ], 'stopoff': [ _std_stopoff, (17,17), None ], 'stopon': [ _std_stopon, (17,17), None ] } class Costume: def __init__(self, filename=None, standard=None): if filename != None: self.picture = pygame.image.load(filename) self.clipped = self.picture self.center = self.picture.get_rect().center self.name = filename else: if standard in _std_costumes: cinfo = _std_costumes[standard] tmp = bz2.decompress(b64.b64decode(cinfo[0])) self.picture = pygame.image.fromstring(tmp, cinfo[1], 'RGBA') self.clipped = self.picture if cinfo[2] == None: self.center = self.picture.get_rect().center else: self.center = cinfo[2] self.name = standard else: self.picture = None self.clipped = None self.center = (0,0) self.name = 'Error' def setCenter(self, center): self.center = center def CostumeFile(filename): return Costume(filename=filename) def CostumeBuiltIn(name): return Costume(standard=name) class BasicSprite(pygame.sprite.Sprite): def __init__(self, location=(0,0), costume=None, pane=None, proto=None, hidden=False): pygame.sprite.Sprite.__init__(self) if (proto == None): self.hidden = hidden self.location = location self.pane = pane self.size = 100 self.direction = 90 self.redraw = True self.rotationStyle = 1 self.costumes = [ costume ] self.costumeNames = { costume.name: 0 } self._setcostume_internal(0) self.onmouseenter = None self.onmouseleave = None self.onmouseclick = None pane.add_sprite(self) else: self.hidden = proto.hidden self.location = proto.location self.pane = proto.pane self.size = proto.size self.direction = proto.direction self.redraw = True self.rotationStyle = proto.rotationStyle self.costumes = list(proto.costumes) self.costumeNames = proto.costumeNames.copy() self._setcostume_internal(proto.costume_num) self.onmouseenter = proto.onmouseenter self.onmouseleave = proto.onmouseleave self.onmouseclick = proto.onmouseclick self.pane.add_sprite(self) def _move_internal(self, pos): self.location = pos; self.rect.center = (self.offset[0]+self.location[0], self.offset[1]-self.location[1]) def _setimage(self): if self.hidden: self.image = pygame.Surface((0,0)) cent = (0,0) else: basepic = self.costumes[self.costume_num].clipped rect = basepic.get_rect() origw = rect.width origh = rect.height cent = self.costumes[self.costume_num].center cent = (cent[0]-origw/2.0, cent[1]-origh/2.0) if (self.size != 100): neww = int(round((self.size/100.0)*basepic.get_rect().width)) newh = int(round((self.size/100.0)*basepic.get_rect().height)) basepic = pygame.transform.scale(basepic, (neww, newh)) cent = (float(cent[0]*neww)/origw, float(cent[1]*newh)/origh) if self.rotationStyle == 1: self.image = pygame.transform.rotate(basepic, 90-self.direction) ang = math.pi*(90-self.direction)/180.0 sinang = math.sin(ang) cosang = math.cos(ang) cent = (cosang*cent[0]-sinang*cent[1], sinang*cent[0]+cosang*cent[1]) elif self.rotationStyle == 2: normalized = self.direction if (normalized < 0): normalized = 360*(1+int(-normalized)/360) + normalized elif normalized >= 360: normalized = normalized - 360*(int(normalized)/360) if normalized <= 180: self.image = basepic else: self.image = pygame.transform.flip(basepic, True, False) cent = (-cent[0], cent[1]) else: self.image = basepic self.rect = self.image.get_rect() self.offset = (int(round(self.pane.origin[0]-cent[0])), int(round(self.pane.origin[1]+cent[1]))) self._move_internal(self.location) self.mask = pygame.mask.from_surface(self.image) self.redraw = False def _setcostume_internal(self, cnum): if (cnum >= 0) and (cnum < len(self.costumes)): self.costume_num = cnum self._setimage() def loadCostume(self, costume): self.costumes.append(costume) self.costumeNames[costume.name] = len(self.costumes)-1; def switchToCostume(self, number): self._setcostume_internal(number) self.redraw = True def setCostumeClip(self, x, y, width, height): c = self.costumes[self.costume_num] c.clipped = c.picture.subsurface(pygame.Rect(x,y,width,height)) c.center = c.clipped.get_rect().center self.redraw = True def resetCostumeClip(self): c = self.costumes[self.costume_num] c.clipped = c.picture c.center = c.clipped.get_rect().center self.redraw = True def hide(self): self.hidden = True self.redraw = True def show(self): self.hidden = False self.redraw = True def goToFront(self): psprites = self.pane.sprites oldLayer = psprites.get_layer_of_sprite(self) psprites.change_layer(self, psprites.get_top_layer()+1) for i in range(oldLayer, len(psprites)): psprites.switch_layer(i+1,i) def goBackLayers(self, num): psprites = self.pane.sprites myLayer = psprites.get_layer_of_sprite(self) while num > 0 and myLayer > 0: psprites.switch_layer(myLayer, myLayer-1) myLayer -= 1 num -= 1 def getLayer(self): psprites = self.pane.sprites myLayer = psprites.get_layer_of_sprite(self) return len(psprites)-myLayer def touching_edge(self): if self.rect.right >= self.pane.rect.width: return True if self.rect.top <= 0: return True if self.rect.left <= 0: return True if self.rect.bottom >= self.pane.rect.height: return True return False def if_on_edge_bounce(self): newdirection = self.direction if self.rect.right >= self.pane.rect.width: newdirection = -self.direction if self.rect.top <= 0: newdirection = 180 - self.direction if self.rect.left <= 0: newdirection = -self.direction if self.rect.bottom >= self.pane.rect.height: newdirection = 180 - self.direction if newdirection != self.direction: self.direction = newdirection self.redraw = True def touching(self, other, offset=(0,0)): offx = self.rect.x+offset[0]-other.rect.x offy = self.rect.y--offset[1]-other.rect.y return other.mask.overlap(self.mask, (offx, offy)) != None def update(self): if self.redraw: self._setimage() class Sprite(BasicSprite): def __init__(self, location=(0,0), costume=None, proto=None, hidden=False): if (proto == None): BasicSprite.__init__(self, location, costume, snappy.stage, hidden=hidden) self.movingToward = None self.arrivalTime = None self.speechBubble = None self.speechExpire = 0 else: BasicSprite.__init__(self, proto=proto, hidden=hidden) self.movingToward = None self.arrivalTime = None self.speechBubble = None self.speechExpire = 0 def move(self, steps): if snappy.stopScripts: raise ExcStopScript() deltax = int(round(steps*math.sin(math.radians(self.direction)))) deltay = int(round(steps*math.cos(math.radians(self.direction)))) self.goTo((self.location[0]+deltax,self.location[1]+deltay)) def turnCW(self, degrees): if snappy.stopScripts: raise ExcStopScript() self.pointInDirection(self.direction+degrees) def turnCCW(self,degrees): if snappy.stopScripts: raise ExcStopScript() self.pointInDirection(self.direction-degrees) def pointInDirection(self, dir): if snappy.stopScripts: raise ExcStopScript() if dir != self.direction: self.direction = dir self.redraw = True if snappy.running: with snappy.frameUpdated: snappy.frameUpdated.wait() def setRotStyle(self, style): if snappy.stopScripts: raise ExcStopScript() if (style != self.rotationStyle): self.rotationStyle = style self.redraw = True def goTo(self, pos): if snappy.stopScripts: raise ExcStopScript() self._move_internal(pos) with snappy.frameUpdated: snappy.frameUpdated.wait() def glideForTo(self, duration, to): self.movingToward = to self.arrivalTime = pygame.time.get_ticks() + duration*1000 while self.movingToward != None: with snappy.frameUpdated: snappy.frameUpdated.wait() if snappy.stopScripts: raise ExcStopScript() def changeXBy(self, deltaX): if snappy.stopScripts: raise ExcStopScript() self.goTo((self.location[0]+deltaX, self.location[1])) def setXTo(self, newX): if snappy.stopScripts: raise ExcStopScript() self.goTo((newX,self.location[1])) def changeYBy(self, deltaY): if snappy.stopScripts: raise ExcStopScript() self.goTo((self.location[0], self.location[1]+deltaY)) def setYTo(self, newY): if snappy.stopScripts: raise ExcStopScript() self.goTo((location[0], newY)) def setSize(self, size): if snappy.stopScripts: raise ExcStopScript() self.size = size self.redraw = True if snappy.running: with snappy.frameUpdated: snappy.frameUpdated.wait() def changeSizeBy(self, delta): self.setSize(self.size + delta) def say(self, text): if snappy.stopScripts: raise ExcStopScript() self.speechBubble = speechbubble(text) self.speechExpire = 0 def sayFor(self, text, duration): self.speechBubble = speechbubble(text) self.speechExpire = pygame.time.get_ticks()+duration*1000 while self.speechBubble != None: with snappy.frameUpdated: snappy.frameUpdated.wait() if snappy.stopScripts: raise ExcStopScript() def wait(self, duration): expire = pygame.time.get_ticks()+duration*1000 while expire > pygame.time.get_ticks(): with snappy.frameUpdated: snappy.frameUpdated.wait() if snappy.stopScripts: raise ExcStopScript() def clone(self): if snappy.stopScripts: raise ExcStopScript() newone = Sprite(proto=self) return newone def update(self): currTime = pygame.time.get_ticks() if self.movingToward != None: if (currTime+snappy.frameperiod >= self.arrivalTime): self._move_internal(self.movingToward) self.movingToward = None else: timespan = self.arrivalTime-currTime fraction = snappy.frameperiod/timespan self._move_internal((self.location[0]+(self.movingToward[0]-self.location[0])*fraction, self.location[1]+(self.movingToward[1]-self.location[1])*fraction)) if self.redraw: self._setimage() if self.speechBubble != None and self.speechExpire > 0 and self.speechExpire < currTime: self.speechBubble = None if self.speechBubble != None: self.speechBubble.drawFor(snappy.stage.worksurface, self) def textToLines(font, text, maxWidth=320): lines = [] start=0 lstart = 0 end=0 nend=0 while start < len(text): # start is 1st char of next line ; nend is next non-space to consider while (nend < len(text) and text[nend]!=' '): nend += 1 # now nend is past next word-to-consider nstart = nend while nstart < len(text) and text[nstart] == ' ': nstart += 1 w = font.size(text[start:nend])[0] if w > maxWidth: if (start == end): lines.append(text[start:nend]) start = nstart else: lines.append(text[start:end]) start = lstart if nstart == len(text): lines.append(text[start:nend]) start = nstart end = nend lstart = nstart nend = nstart return lines def renderText(font, text, justify=0, maxWidth=320): lines = textToLines(font, text, maxWidth) s = [ font.render(lines[i], True, (0,0,0)) for i in range(len(lines)) ] width = max([s[i].get_width() for i in range(len(s))]) height = font.get_linesize()*len(s) ret = pygame.Surface((width,height)) ret.fill((255,255,255)) for i in range(len(s)): if justify == 0: x=0 elif justify == 1: x=int((width-s[i].get_width())/2) else: x=width-s[i].get_width() ret.blit(s[i], (x, i*font.get_linesize())) return ret def updateall(): for p in snappy.panes: p.render(snappy.screen) pygame.display.flip() # make this a class, and init with icons and rect - could be a sprite w/update? def activeicon(activeflag, iconoff, iconon, mousepos, rect): overicon = rect.collidepoint(mousepos) if not activeflag and overicon: activeflag = True snappy.screen.blit(iconon, rect) elif activeflag and not overicon: activeflag = False snappy.screen.blit(iconoff, rect) return activeflag eventHandlers = {} def registerGeneric(name, function): global eventHandlers if name in eventHandlers: eventHandlers[name].append(function) else: eventHandlers[name] = [ function ] def startOnGreenFlag(): return lambda fn : registerGeneric('s-greenFlag', fn) def startOnReceiving(signalName): return lambda fn : registerGeneric('b-'+signalName, fn) def startOnKey(key): return lambda fn : registerGeneric('k-'+key, fn) def manager(fn): try: fn() except ExcStopScript: pass snappy.threads.remove(threading.current_thread()) def launch(fn): t = threading.Thread(target=manager, args=(fn,)) t.daemon = True snappy.threads.append(t) t.start() def dohandlers(name): global eventHandlers if name in eventHandlers: for h in eventHandlers[name]: launch(h) # else: # print('unknown event: '+name) def broadcast(signalName): snappy.myEvents.append('b-'+signalName) def stop_all_scripts(): snappy.stopScripts = True def dogame(): snappy.running = 1 flagactive=False mdownsprite = None while snappy.running: eList = pygame.event.get() for e in eList: if e.type == pygame.KEYDOWN: if e.key >=0 and e.key < 256: dohandlers('k-'+chr(e.key)) elif e.key == pygame.K_LEFT: dohandlers('k-left') elif e.key == pygame.K_RIGHT: dohandlers('k-right') elif e.key == pygame.K_UP: dohandlers('k-up') elif e.key == pygame.K_DOWN: dohandlers('k-down') if e.type == pygame.MOUSEBUTTONDOWN and e.button == 1: mdownsprite = snappy.check_mouse(e.pos) if e.type == pygame.MOUSEBUTTONUP and e.button == 1: if snappy.check_mouse(e.pos) == mdownsprite and mdownsprite != None: if mdownsprite.onmouseclick != None: mdownsprite.onmouseclick() mdownsprite = None for e in snappy.myEvents: dohandlers(e) snappy.myEvents = [] oversprite = snappy.check_mouse(pygame.mouse.get_pos()) if snappy.oversprite != oversprite: if snappy.oversprite != None and snappy.oversprite.onmouseleave != None: snappy.oversprite.onmouseleave() if oversprite != None and oversprite.onmouseenter != None: oversprite.onmouseenter() snappy.oversprite = oversprite updateall() with snappy.frameUpdated: snappy.frameUpdated.notifyAll() snappy.clock.tick(snappy.framerate) pts_ul = [ (7,0), (5,0), (3,1), (1,3), (0,5), (0,7), (4,7), (5,5), (7,4)] pts_sp = [(22, 0), (12, 15), (37, 0), (31, 0), (24, 3), (26, 0)] red = (255,0,0) white = (255,255,255) def outline(color, rect, toRight=True): # for now fixed padding: 3 at top and bottom, 5 on sides padl, padt, padr, padb = 5, 3, 5, 3 bubble_sz = (rect.width+10+padl+padr, rect.height+10+padt+padb) if bubble_sz[0] < 52: bubble_sz = (52, bubble_sz[1]) surf = pygame.Surface((bubble_sz[0],bubble_sz[1]+15)) surf.fill((255,255,255)) pygame.draw.polygon(surf, color, pts_ul, 0) surf.fill(color, pygame.Rect(8, 0, bubble_sz[0]-16, 5)) pygame.draw.polygon(surf, color, map( lambda(p): (bubble_sz[0]-1-p[0], p[1]), pts_ul), 0) surf.fill(color, pygame.Rect(bubble_sz[0]-5, 8, 5, bubble_sz[1]-16)) pygame.draw.polygon(surf, color, map( lambda(p): (bubble_sz[0]-1-p[0], bubble_sz[1]-1-p[1]), pts_ul), 0) # bottom for speech bubble if toRight: surf.fill(color, pygame.Rect(8, bubble_sz[1]-5, 14, 5)) pygame.draw.polygon(surf, color, map( lambda(p): (p[0], bubble_sz[1]-5+p[1]), pts_sp), 0) surf.fill(color, pygame.Rect(32, bubble_sz[1]-5, bubble_sz[0]-40, 5)) else: surf.fill(color, pygame.Rect(8, bubble_sz[1]-5, bubble_sz[0]-40, 5)) pygame.draw.polygon(surf, color, map( lambda(p): (bubble_sz[0]-1-p[0], bubble_sz[1]-5+p[1]), pts_sp), 0) surf.fill(color, pygame.Rect(bubble_sz[0]-22, bubble_sz[1]-5, 14, 5)) # end of speech bubble bottom pygame.draw.polygon(surf, color, map( lambda(p): (p[0], bubble_sz[1]-1-p[1]), pts_ul), 0) surf.fill(color, pygame.Rect(0, 8, 5, bubble_sz[1]-16)) return surf def speech(text): sp_surf = renderText(snappy.sp_font, text, 1, 160) bubble_surf = outline((140,140,140),sp_surf.get_rect()) bubble_surf.blit(sp_surf, ((bubble_surf.get_width()-sp_surf.get_width())/2,8)) sec.stage_back.blit(bubble_surf, (10,10)) class speechbubble: def __init__(self, text): self.text = text self.textsurf = renderText(snappy.sp_font, text, 1, 130) self.bubble_toright = outline((190,190,190),self.textsurf.get_rect(),True) self.bubble_toright.blit(self.textsurf, ((self.bubble_toright.get_width()-self.textsurf.get_width())/2, 8)) self.bubble_toleft = None self.width = self.bubble_toright.get_rect().width def drawFor(self, surf, sprite): x = sprite.rect.centerx y = sprite.rect.top - self.bubble_toright.get_rect().height if (y < 0): y = 0 if (x + self.width) <= 480: surf.blit(self.bubble_toright, (x,y)) else: if self.bubble_toleft == None: self.bubble_toleft = outline((190,190,190),self.textsurf.get_rect(),False) self.bubble_toleft.blit(self.textsurf, ((self.bubble_toleft.get_width()-self.textsurf.get_width())/2, 8)) surf.blit(self.bubble_toleft, (x-self.width,y)) def start(): if snappy.use_thread: t = threading.Thread(target=dogame) t.daemon = True t.start() else: dogame() def oldstart(): sec.stage_rect = pygame.Rect(0,33,480,360) sec.stage_surf = pygame.Surface((480,360)) sec.stage_back = pygame.Surface((480,360)) sec.stage_back.fill((255,255,255)) sec.stage_surf.blit(sec.stage_back, (0,0)) background = pygame.Surface(snappy.screen.get_size()) background = background.convert() # background.blit(topbar_bg, (0,0)) background.blit(sec.stage_surf, sec.stage_rect) snappy.screen.blit(background, (0,0)) pygame.display.flip() if snappy.use_thread: t = threading.Thread(target=dogame) t.daemon = True t.start() else: dogame() def encode_image(fname): s = pygame.image.load(fname) e = b64.b64encode(bz2.compress(pygame.image.tostring(s, 'RGBA'))) return e init() # TODO: Sprite costume from part of an image # TODO: Better costume handling (names, etc.) # TODO: Fix cloning of event handlers (events go to prev object) # TODO: Stop/Pause signs # TODO: Better thread management