from sys import argv
from panda3d.core import Vec3
from pandac.PandaModules import loadPrcFileData
loadPrcFileData('configurate', 'window-title Loading')
from direct.directbase import DirectStart
from direct.task import Task
from direct.actor.Actor import Actor
from direct.gui.DirectGui import *
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.showbase.InputStateGlobal import inputState
from direct.controls.GravityWalker import GravityWalker
from direct.showbase import DirectObject
from direct.interval.IntervalGlobal import *
import urllib, os, __main__, random
from pandac.PandaModules import *
from random import choice

base.disableMouse()
title = OnscreenImage(image='phase_3/maps/Game_Toontown_Logo_1.jpg', pos=(0, 0, 0.0), parent=render2d)
base.graphicsEngine.renderFrame()
base.graphicsEngine.renderFrame()
base.graphicsEngine.renderFrame()
base.graphicsEngine.renderFrame()
title.destroy()
props = WindowProperties()
props.setTitle('League Of Toons')
base.win.requestProperties(props)
from panda3d.core import *

class guitools():

    def createFrame(self, filepath, resX = None, resY = None):
        yresolution = 600
        tex = loader.loadTexture(filepath)
        tex.setBorderColor(Vec4(0, 0, 0, 0))
        tex.setWrapU(Texture.WMRepeat)
        tex.setWrapV(Texture.WMRepeat)
        cm = CardMaker(filepath + ' card')
        if resX == None:
            resX = tex.getOrigFileXSize()
        if resY == None:
            resY = tex.getOrigFileySize()
        cm.setFrame(-resX, resX, -resY, resY)
        card = NodePath(cm.generate())
        card.setTexture(tex)
        card.flattenLight()
        card.setScale(card.getScale() / yresolution)
        return card

    def createButton(self, cmd, position, hpr, model, buttonImgs, scale, colour = (1, 1, 1, 1), text = ''):
        ButtonImage = loader.loadModel(model)
        ButtonImageUp = ButtonImage.find('**/' + buttonImgs[0])
        ButtonImageDown = ButtonImage.find('**/' + buttonImgs[1])
        ButtonImageRollover = ButtonImage.find('**/' + buttonImgs[-1])
        return DirectButton(frameSize=None, image=(ButtonImageUp, ButtonImageDown, ButtonImageRollover), relief=None, command=cmd, geom=None, pad=(0.01, 0.01), text=text, suppressKeys=0, pos=position, hpr=hpr, text_fg=(1, 1, 1, 1), color=colour, text_scale=0.059, borderWidth=(0.13, 0.01), scale=scale)

class ClassicBook():
    Book = loader.loadModel('phase_3.5/models/gui/stickerbook_gui.bam')

    def __beingOpened__(self):
        self.BookClose.hide()
        try:
            base.localAvatar.b_setAnimState('OpenBook')
        except:
            pass

        return True

    def __openBook__(self):
        seq = Sequence()
        seq.append(Func(self.__beingOpened__))
        seq.append(Wait(0.3))
        seq.append(Func(self.__addNavs__))
        seq.start()
        return True

    def __delNavs__(self):
        self.bg[0].hide()
        self.bg[1].hide()
        self.BookOpen.removeNode()
        self.__addOnButton__()
        try:
            base.localAvatar.b_setAnimState('CloseBook')
            base.localAvatar.physControls.enableAvatarControls()
        except:
            pass

        return True

    def __addNavs__(self):
        self.BookClose.removeNode()
        self.bg = []
        for b in range(2):
            self.bg.append(Guitools.createFrame('phase_3.5/maps/Book.jpg', base.win.getXSize() + 160, base.win.getYSize() + 125))
            self.bg.append(Guitools.createFrame('phase_3.5/maps/big_book.jpg',600,450))
            self.bg[b].reparentTo(aspect2d)

        self.bg[0].setPos(0, 0, 0)
        self.bg[1].setPos(0, 0, 0.1)
        self.BookOpen = DirectButton(frameSize=None, image=(self.Book.find('**/BookIcon_OPEN'), self.Book.find('**/BookIcon_CLSD'), self.Book.find('**/BookIcon_RLVR2')), relief=None, command=self.__delNavs__, text='', text_pos=(0, -0.015), geom=None, scale=0.305, pad=(0.01, 0.01), suppressKeys=0, pos=(1.16, 0, -0.83), hpr=(0, 0, 0), text_scale=0.06, borderWidth=(0.015, 0.01))
        try:
            base.localAvatar.b_setAnimState('ReadBook')
        except:
            pass

        return True

    def __addOnButton__(self):
        self.BookClose = DirectButton(frameSize=None, image=(self.Book.find('**/BookIcon_CLSD'), self.Book.find('**/BookIcon_OPEN'), self.Book.find('**/BookIcon_RLVR')), relief=None, command=self.__openBook__, text='', text_pos=(0, -0.015), geom=None, scale=0.305, pad=(0.01, 0.01), suppressKeys=0, pos=(1.16, 0, -0.83), hpr=(0, 0, 0), text_scale=0.06, borderWidth=(0.015, 0.01))
        return True

    def __init__(self):
        self.__addOnButton__()

Guitools = guitools()
BookGui = ClassicBook()
base.disableMouse()
legsAnimDict = {'right-hand-start': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-hand-start.bam',
 'firehose': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_firehose.bam',
 'rotateL-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_rotateL-putt.bam',
 'slip-forward': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_slip-forward.bam',
 'catch-eatnrun': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_eatnrun.bam',
 'tickle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_tickle.bam',
 'water-gun': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_water-gun.bam',
 'leverNeutral': 'phase_10/models/char/tt_a_chr_dgs_shorts_legs_leverNeutral.bam',
 'swim': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_swim.bam',
 'catch-run': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_gamerun.bam',
 'sad-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_sad-neutral.bam',
 'pet-loop': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_petloop.bam',
 'jump-squat': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-zstart.bam',
 'wave': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_wave.bam',
 'reel-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_reelneutral.bam',
 'pole-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_poleneutral.bam',
 'bank': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_jellybeanJar.bam',
 'scientistGame': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistGame.bam',
 'right-hand': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-hand.bam',
 'lookloop-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_lookloop-putt.bam',
 'victory': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_victory-dance.bam',
 'lose': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_lose.bam',
 'cringe': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_cringe.bam',
 'right': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_right.bam',
 'headdown-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_headdown-putt.bam',
 'conked': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_conked.bam',
 'jump': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump.bam',
 'into-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_into-putt.bam',
 'fish-end': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fishEND.bam',
 'running-jump-land': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_leap_zend.bam',
 'shrug': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_shrug.bam',
 'sprinkle-dust': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_sprinkle-dust.bam',
 'hold-bottle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_hold-bottle.bam',
 'takePhone': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_takePhone.bam',
 'melt': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_melt.bam',
 'pet-start': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_petin.bam',
 'look-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_look-putt.bam',
 'loop-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_loop-putt.bam',
 'good-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_good-putt.bam',
 'juggle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_juggle.bam',
 'run': 'phase_3/models/char/tt_a_chr_dgs_shorts_legs_run.bam',
 'pushbutton': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_press-button.bam',
 'sidestep-right': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-back-right.bam',
 'water': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_water.bam',
 'right-point-start': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-point-start.bam',
 'bad-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_bad-putt.bam',
 'struggle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_struggle.bam',
 'running-jump': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_running-jump.bam',
 'callPet': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_callPet.bam',
 'throw': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_pie-throw.bam',
 'catch-eatneutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_eat_neutral.bam',
 'tug-o-war': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_tug-o-war.bam',
 'bow': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_bow.bam',
 'swing': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_swing.bam',
 'climb': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_climb.bam',
 'scientistWork': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistWork.bam',
 'think': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_think.bam',
 'catch-intro-throw': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_gameThrow.bam',
 'walk': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_walk.bam',
 'down': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_down.bam',
 'pole': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_pole.bam',
 'periscope': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_periscope.bam',
 'duck': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_duck.bam',
 'curtsy': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_curtsy.bam',
 'jump-land': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-zend.bam',
 'loop-dig': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_loop_dig.bam',
 'angry': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_angry.bam',
 'bored': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_bored.bam',
 'swing-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_swing-putt.bam',
 'pet-end': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_petend.bam',
 'spit': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_spit.bam',
 'right-point': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-point.bam',
 'start-dig': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_into_dig.bam',
 'castlong': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_castlong.bam',
 'confused': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_confused.bam',
 'neutral': 'phase_3/models/char/tt_a_chr_dgs_shorts_legs_neutral.bam',
 'jump-idle': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-zhang.bam',
 'reel': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_reel.bam',
 'slip-backward': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_slip-backward.bam',
 'sound': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_shout.bam',
 'sidestep-left': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_sidestep-left.bam',
 'up': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_up.bam',
 'fish-again': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fishAGAIN.bam',
 'cast': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_cast.bam',
 'phoneBack': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_phoneBack.bam',
 'phoneNeutral': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_phoneNeutral.bam',
 'scientistJealous': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistJealous.bam',
 'battlecast': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fish.bam',
 'sit-start': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_intoSit.bam',
 'toss': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_toss.bam',
 'happy-dance': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_happy-dance.bam',
 'running-jump-squat': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_leap_zstart.bam',
 'teleport': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_teleport.bam',
 'sit': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_sit.bam',
 'sad-walk': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_losewalk.bam',
 'give-props-start': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_give-props-start.bam',
 'book': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_book.bam',
 'running-jump-idle': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_leap_zhang.bam',
 'scientistEmcee': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistEmcee.bam',
 'leverPull': 'phase_10/models/char/tt_a_chr_dgs_shorts_legs_leverPull.bam',
 'tutorial-neutral': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_tutorial-neutral.bam',
 'badloop-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_badloop-putt.bam',
 'give-props': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_give-props.bam',
 'hold-magnet': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_hold-magnet.bam',
 'hypnotize': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_hypnotize.bam',
 'left-point': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_left-point.bam',
 'leverReach': 'phase_10/models/char/tt_a_chr_dgs_shorts_legs_leverReach.bam',
 'feedPet': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_feedPet.bam',
 'reel-H': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_reelH.bam',
 'applause': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_applause.bam',
 'smooch': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_smooch.bam',
 'rotateR-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_rotateR-putt.bam',
 'fish-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fishneutral.bam',
 'push': 'phase_9/models/char/tt_a_chr_dgs_shorts_legs_push.bam',
 'catch-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_gameneutral.bam',
 'left': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_left.bam'}
torsoAnimDict = {'right-hand-start': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-hand-start.bam',
 'firehose': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_firehose.bam',
 'rotateL-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_rotateL-putt.bam',
 'slip-forward': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_slip-forward.bam',
 'catch-eatnrun': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_eatnrun.bam',
 'tickle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_tickle.bam',
 'water-gun': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_water-gun.bam',
 'leverNeutral': 'phase_10/models/char/tt_a_chr_dgl_shorts_torso_leverNeutral.bam',
 'swim': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_swim.bam',
 'catch-run': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_gamerun.bam',
 'sad-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_sad-neutral.bam',
 'pet-loop': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_petloop.bam',
 'jump-squat': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-zstart.bam',
 'wave': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_wave.bam',
 'reel-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_reelneutral.bam',
 'pole-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_poleneutral.bam',
 'bank': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_jellybeanJar.bam',
 'scientistGame': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistGame.bam',
 'right-hand': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-hand.bam',
 'lookloop-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_lookloop-putt.bam',
 'victory': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_victory-dance.bam',
 'lose': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_lose.bam',
 'cringe': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_cringe.bam',
 'right': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_right.bam',
 'headdown-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_headdown-putt.bam',
 'conked': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_conked.bam',
 'jump': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump.bam',
 'into-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_into-putt.bam',
 'fish-end': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fishEND.bam',
 'running-jump-land': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_leap_zend.bam',
 'shrug': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_shrug.bam',
 'sprinkle-dust': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_sprinkle-dust.bam',
 'hold-bottle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_hold-bottle.bam',
 'takePhone': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_takePhone.bam',
 'melt': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_melt.bam',
 'pet-start': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_petin.bam',
 'look-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_look-putt.bam',
 'loop-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_loop-putt.bam',
 'good-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_good-putt.bam',
 'juggle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_juggle.bam',
 'run': 'phase_3/models/char/tt_a_chr_dgl_shorts_torso_run.bam',
 'pushbutton': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_press-button.bam',
 'sidestep-right': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-back-right.bam',
 'water': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_water.bam',
 'right-point-start': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-point-start.bam',
 'bad-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_bad-putt.bam',
 'struggle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_struggle.bam',
 'running-jump': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_running-jump.bam',
 'callPet': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_callPet.bam',
 'throw': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_pie-throw.bam',
 'catch-eatneutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_eat_neutral.bam',
 'tug-o-war': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_tug-o-war.bam',
 'bow': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_bow.bam',
 'swing': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_swing.bam',
 'climb': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_climb.bam',
 'scientistWork': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistWork.bam',
 'think': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_think.bam',
 'catch-intro-throw': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_gameThrow.bam',
 'walk': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_walk.bam',
 'down': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_down.bam',
 'pole': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_pole.bam',
 'periscope': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_periscope.bam',
 'duck': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_duck.bam',
 'curtsy': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_curtsy.bam',
 'jump-land': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-zend.bam',
 'loop-dig': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_loop_dig.bam',
 'angry': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_angry.bam',
 'bored': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_bored.bam',
 'swing-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_swing-putt.bam',
 'pet-end': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_petend.bam',
 'spit': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_spit.bam',
 'right-point': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-point.bam',
 'start-dig': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_into_dig.bam',
 'castlong': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_castlong.bam',
 'confused': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_confused.bam',
 'neutral': 'phase_3/models/char/tt_a_chr_dgl_shorts_torso_neutral.bam',
 'jump-idle': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-zhang.bam',
 'reel': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_reel.bam',
 'slip-backward': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_slip-backward.bam',
 'sound': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_shout.bam',
 'sidestep-left': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_sidestep-left.bam',
 'up': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_up.bam',
 'fish-again': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fishAGAIN.bam',
 'cast': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_cast.bam',
 'phoneBack': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_phoneBack.bam',
 'phoneNeutral': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_phoneNeutral.bam',
 'scientistJealous': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistJealous.bam',
 'battlecast': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fish.bam',
 'sit-start': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_intoSit.bam',
 'toss': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_toss.bam',
 'happy-dance': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_happy-dance.bam',
 'running-jump-squat': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_leap_zstart.bam',
 'teleport': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_teleport.bam',
 'sit': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_sit.bam',
 'sad-walk': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_losewalk.bam',
 'give-props-start': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_give-props-start.bam',
 'book': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_book.bam',
 'running-jump-idle': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_leap_zhang.bam',
 'scientistEmcee': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistEmcee.bam',
 'leverPull': 'phase_10/models/char/tt_a_chr_dgl_shorts_torso_leverPull.bam',
 'tutorial-neutral': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_tutorial-neutral.bam',
 'badloop-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_badloop-putt.bam',
 'give-props': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_give-props.bam',
 'hold-magnet': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_hold-magnet.bam',
 'hypnotize': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_hypnotize.bam',
 'left-point': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_left-point.bam',
 'leverReach': 'phase_10/models/char/tt_a_chr_dgl_shorts_torso_leverReach.bam',
 'feedPet': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_feedPet.bam',
 'reel-H': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_reelH.bam',
 'applause': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_applause.bam',
 'smooch': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_smooch.bam',
 'rotateR-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_rotateR-putt.bam',
 'fish-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fishneutral.bam',
 'push': 'phase_9/models/char/tt_a_chr_dgl_shorts_torso_push.bam',
 'catch-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_gameneutral.bam',
 'left': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_left.bam'}
DuckHead = loader.loadModel('phase_3/models/char/duck-heads-1000.bam')
otherParts = DuckHead.findAllMatches('**/*long*')
for partNum in range(0, otherParts.getNumPaths()):
    otherParts.getPath(partNum).removeNode()

ntrlMuzzle = DuckHead.find('**/*muzzle*neutral')
otherParts = DuckHead.findAllMatches('**/*muzzle*')
for partNum in range(0, otherParts.getNumPaths()):
    part = otherParts.getPath(partNum)
    if part != ntrlMuzzle:
        otherParts.getPath(partNum).removeNode()

DuckTorso = loader.loadModel('phase_3/models/char/tt_a_chr_dgl_shorts_torso_1000.bam')
DuckLegs = loader.loadModel('phase_3/models/char/tt_a_chr_dgs_shorts_legs_1000.bam')
otherParts = DuckLegs.findAllMatches('**/boots*') + DuckLegs.findAllMatches('**/shoes')
for partNum in range(0, otherParts.getNumPaths()):
    otherParts.getPath(partNum).removeNode()

DuckBody = Actor({'head': DuckHead,
 'torso': DuckTorso,
 'legs': DuckLegs}, {'torso': torsoAnimDict,
 'legs': legsAnimDict})
DuckBody.attach('head', 'torso', 'def_head')
DuckBody.attach('torso', 'legs', 'joint_hips')
gloves = DuckBody.findAllMatches('**/hands')
ears = DuckBody.findAllMatches('**/*ears*')
head = DuckBody.findAllMatches('**/head-*')
sleeves = DuckBody.findAllMatches('**/sleeves')
shirt = DuckBody.findAllMatches('**/torso-top')
shorts = DuckBody.findAllMatches('**/torso-bot')
neck = DuckBody.findAllMatches('**/neck')
arms = DuckBody.findAllMatches('**/arms')
legs = DuckBody.findAllMatches('**/legs')
feet = DuckBody.findAllMatches('**/feet')
bodyNodes = []
bodyNodes += [gloves]
bodyNodes += [head, ears]
bodyNodes += [sleeves, shirt, shorts]
bodyNodes += [neck,
 arms,
 legs,
 feet]
bodyNodes[0].setColor(1, 1, 1, 1)
bodyNodes[1].setColor(1, 0.5, 0, 1)
bodyNodes[2].setColor(1, 0.5, 0, 1)
bodyNodes[3].setColor(0.264, 0.308, 0.676, 1)
bodyNodes[4].setColor(0.264, 0.308, 0.676, 1)
bodyNodes[5].setColor(1, 1, 1, 1)
bodyNodes[6].setColor(1, 0.5, 0, 1)
bodyNodes[7].setColor(1, 0.5, 0, 1)
bodyNodes[8].setColor(0.276, 0.872, 0.36, 1)
bodyNodes[9].setColor(0.276, 0.872, 0.36, 1)
topTex = loader.loadTexture('phase_3/maps/desat_shirt_5.jpg')
botTex = loader.loadTexture('phase_4/maps/CowboyShorts1.jpg')
sleeveTex = loader.loadTexture('phase_3/maps/desat_sleeve_5.jpg')
bodyNodes[3].setTexture(sleeveTex, 1)
bodyNodes[4].setTexture(topTex, 1)
bodyNodes[5].setTexture(botTex, 1)
DuckBody.reparentTo(render)
geom = DuckBody.getGeomNode()
geom.getChild(0).setSx(0.730000019073)
geom.getChild(0).setSz(0.730000019073)
offset = 3.2375
base.camera.reparentTo(DuckBody)
base.camera.setPos(0, -9.0 - offset, offset)
wallBitmask = BitMask32(1)
floorBitmask = BitMask32(2)
base.cTrav = CollisionTraverser()
base.camera.hide()

def getAirborneHeight():
    return offset + 0.025

walkControls = GravityWalker(legacyLifter=True)
walkControls.setWallBitMask(wallBitmask)
walkControls.setFloorBitMask(floorBitmask)
walkControls.setWalkSpeed(16.0, 24.0, 8.0, 80.0)
walkControls.initializeCollisions(base.cTrav, DuckBody, floorOffset=0.025, reach=4.0)
walkControls.setAirborneHeightFunc(getAirborneHeight)
walkControls.enableAvatarControls()
DuckBody.physControls = walkControls

def setWatchKey(key, input, keyMapName):

    def watchKey(active = True):
        if active == True:
            inputState.set(input, True)
            keyMap[keyMapName] = 1
        else:
            inputState.set(input, False)
            keyMap[keyMapName] = 0

    base.accept(key, watchKey, [True])
    base.accept(key + '-up', watchKey, [False])

keyMap = {'left': 0,
 'right': 0,
 'forward': 0,
 'backward': 0,
 'control': 0}
setWatchKey('arrow_up', 'forward', 'forward')
setWatchKey('control-arrow_up', 'forward', 'forward')
setWatchKey('alt-arrow_up', 'forward', 'forward')
setWatchKey('shift-arrow_up', 'forward', 'forward')
setWatchKey('arrow_down', 'reverse', 'backward')
setWatchKey('control-arrow_down', 'reverse', 'backward')
setWatchKey('alt-arrow_down', 'reverse', 'backward')
setWatchKey('shift-arrow_down', 'reverse', 'backward')
setWatchKey('arrow_left', 'turnLeft', 'left')
setWatchKey('control-arrow_left', 'turnLeft', 'left')
setWatchKey('alt-arrow_left', 'turnLeft', 'left')
setWatchKey('shift-arrow_left', 'turnLeft', 'left')
setWatchKey('arrow_right', 'turnRight', 'right')
setWatchKey('control-arrow_right', 'turnRight', 'right')
setWatchKey('alt-arrow_right', 'turnRight', 'right')
setWatchKey('shift-arrow_right', 'turnRight', 'right')
setWatchKey('control', 'jump', 'control')
movingNeutral, movingForward = (False, False)
movingRotation, movingBackward = (False, False)
movingJumping = False

def setMovementAnimation(loopName, playRate = 1.0):
    global movingRotation
    global movingBackward
    global movingForward
    global movingNeutral
    global movingJumping
    if 'jump' in loopName:
        movingJumping = True
        movingForward = False
        movingNeutral = False
        movingRotation = False
        movingBackward = False
    elif loopName == 'run':
        movingJumping = False
        movingForward = True
        movingNeutral = False
        movingRotation = False
        movingBackward = False
    elif loopName == 'walk':
        movingJumping = False
        movingForward = False
        movingNeutral = False
        if playRate == -1.0:
            movingBackward = True
            movingRotation = False
        else:
            movingBackward = False
            movingRotation = True
    elif loopName == 'neutral':
        movingJumping = False
        movingForward = False
        movingNeutral = True
        movingRotation = False
        movingBackward = False
    else:
        movingJumping = False
        movingForward = False
        movingNeutral = False
        movingRotation = False
        movingBackward = False
    ActorInterval(DuckBody, loopName, playRate=playRate).loop()

def handleMovement(task):
    if keyMap['control'] == 1:
        if keyMap['forward'] or keyMap['backward'] or keyMap['left'] or keyMap['right']:
            if movingJumping == False:
                if DuckBody.physControls.isAirborne:
                    setMovementAnimation('running-jump-idle')
                elif keyMap['forward']:
                    if movingForward == False:
                        setMovementAnimation('run')
                elif keyMap['backward']:
                    if movingBackward == False:
                        setMovementAnimation('walk', playRate=-1.0)
                elif keyMap['left'] or keyMap['right']:
                    if movingRotation == False:
                        setMovementAnimation('walk')
            elif not DuckBody.physControls.isAirborne:
                if keyMap['forward']:
                    if movingForward == False:
                        setMovementAnimation('run')
                elif keyMap['backward']:
                    if movingBackward == False:
                        setMovementAnimation('walk', playRate=-1.0)
                elif keyMap['left'] or keyMap['right']:
                    if movingRotation == False:
                        setMovementAnimation('walk')
        elif movingJumping == False:
            if DuckBody.physControls.isAirborne:
                setMovementAnimation('jump-idle')
            elif movingNeutral == False:
                setMovementAnimation('neutral')
        elif not DuckBody.physControls.isAirborne:
            if movingNeutral == False:
                setMovementAnimation('neutral')
                fsrun.stop()
    elif keyMap['forward'] == 1:
        if movingForward == False:
            if not DuckBody.physControls.isAirborne:
                setMovementAnimation('run')
    elif keyMap['backward'] == 1:
        if movingBackward == False:
            if not DuckBody.physControls.isAirborne:
                setMovementAnimation('walk', playRate=-1.0)
    elif keyMap['left'] or keyMap['right']:
        if movingRotation == False:
            if not DuckBody.physControls.isAirborne:
                setMovementAnimation('walk')
                fswalk = loader.loadSfx('phase_3.5/audio/sfx/AV_footstep_walkloop.wav')
    elif not DuckBody.physControls.isAirborne:
        if movingNeutral == False:
            setMovementAnimation('neutral')
    return Task.cont

base.taskMgr.add(handleMovement, 'controlManager')

def collisionsOn():
    DuckBody.physControls.setCollisionsActive(True)
    DuckBody.physControls.isAirborne = True

def collisionsOff():
    DuckBody.physControls.setCollisionsActive(False)
    DuckBody.physControls.isAirborne = True

def toggleCollisions():
    if DuckBody.physControls.getCollisionsActive():
        DuckBody.physControls.setCollisionsActive(False)
        DuckBody.physControls.isAirborne = True
    else:
        DuckBody.physControls.setCollisionsActive(True)
        DuckBody.physControls.isAirborne = True

base.accept('f1', toggleCollisions)
DuckBody.collisionsOn = collisionsOn
DuckBody.collisionsOff = collisionsOff
DuckBody.toggleCollisions = toggleCollisions
fsrun = loader.loadSfx('phase_3/audio/bgm/tt_theme.mid')
fsrun.setLoop(True)
fsrun.play()
localAvatar = DuckBody
base.localAvatar = localAvatar
localAvatar.physControls.placeOnFloor()
onScreenDebug.enabled = False

def updateOnScreenDebug(task):
    onScreenDebug.add('Avatar Position', localAvatar.getPos())
    onScreenDebug.add('Avatar Angle', localAvatar.getHpr())
    return Task.cont

MickeyFont = loader.loadFont('phase_3/models/fonts/MickeyFont.bam')

class EnvironmentTTC():

    def __init__(self):
        self.modeldict = {}
        self.LoadTTC()

    def LoadTTC(self):
        self.modelloader('Sky', 'phase_3.5/models/props/TT_sky.bam', render, 0, 0, 0, 0, 0, 0, 5, 5, 5)
        Clouds1 = self.modeldict['Sky'].find('**/cloud1')
        Clouds2 = self.modeldict['Sky'].find('**/cloud2')
        Clouds1.setScale(0.6, 0.6, 0.6)
        Clouds2.setScale(0.9, 0.9, 0.9)
        Clouds1Spin = Clouds1.hprInterval(360, Vec3(60, 0, 0))
        Clouds1Spin.loop()
        Clouds2Spin = Clouds2.hprInterval(360, Vec3(-60, 0, 0))
        Clouds2Spin.loop()
        self.modelloader('TTC', 'phase_4/models/neighborhoods/toontown_central.bam', render, 0, 0, 0, -90, 0, 0, 1, 1, 1)
        self.modeldict['TTC'].setTransparency(TransparencyAttrib.MBinary, 1)
        self.modelloader('ToonHQ', 'phase_3.5/models/modules/hqTT.bam', render, 24.6425, 24.8587, 4.00001, 135, 0, 0, 1, 1, 1)
        self.modeldict['ToonHQ'].find('**/doorFrameHoleRight_0').hide()
        self.modeldict['ToonHQ'].find('**/doorFrameHoleLeft_0').hide()
        self.modeldict['ToonHQ'].find('**/doorFrameHoleRight_1').hide()
        self.modeldict['ToonHQ'].find('**/doorFrameHoleLeft_1').hide()
        self.modelloader('Partygate', 'phase_4/models/modules/partyGate_TT.bam', render, 77.935, -159.939, 2.70141, 195, 0, 0, 1, 1, 1)
        self.modelloader('Petshop', 'phase_4/models/modules/PetShopExterior_TT.bam', render, -124.375, 74.3749, 0.5, 49, 0, 0, 1, 1, 1)
        self.modelloaderanimate('PetshopFish', 'phase_4/models/props/exteriorfish-zero.bam', 'phase_4/models/props/exteriorfish-swim.bam', self.modeldict['Petshop'], 0, 0, 0, 0, 0, 0, 1, 1, 1, 'swim')
        Petsign1 = self.modeldict['Petshop'].find('**/sign_origin')
        self.textloader('Pettext2', 'Pettextnode2', 'Pettextname2', 'Pet Shop', MickeyFont, Petsign1, -5, -0.2, 0.2, 0, 0, 0, 2, 2, 2, 0.9, 0.88, 0.1)
        Petdoor = self.modeldict['Petshop'].find('**/door_origin')
        self.modelloadercopyto('Door1', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_round_ur', Petdoor, 0, -0.1, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door1'].setColor(1, 0.87, 0.38)
        self.modelloader('Clothingshop', 'phase_4/models/modules/clothshopTT.bam', render, 106.265, 160.831, 3, -30, 0, 0, 1, 1, 1)
        Clothingsign1 = self.modeldict['Clothingshop'].find('**/sign_origin')
        self.textloader('Clothingtext2', 'Clothingtextnode2', 'Clothingtextname2', 'Clothing Shop', MickeyFont, Clothingsign1, -6.7, -0.2, 0.1, 0, 0, 0, 1.5, 1.5, 1.5, 0.88, 0.45, 0.38)
        Clothingdoor = self.modeldict['Clothingshop'].find('**/door_origin')
        self.modelloadercopyto('Door2', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_clothshop', Clothingdoor, 0, -0.1, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door2'].setColor(0.88, 0.45, 0.38)
        self.modelloader('Toonhall', 'phase_4/models/modules/toonhall.bam', render, 116.66, 24.29, 4, -90, 0, 0, 1, 1, 1)
        Hallsign = self.modeldict['Toonhall'].find('**/sign_origin')
        self.textloader('Halltext1', 'Halltextnode1', 'Halltextname1', 'Mickey', MickeyFont, Hallsign, -5, -0.2, -0.5, 0, 0, 0, 2.5, 2.5, 2.5, 0.9, 0.88, 0.1)
        self.textloader('Halltext2', 'Halltextnode2', 'Halltextname2', 'Toon Hall', MickeyFont, Hallsign, -7, -0.2, -3, 0, 0, 0, 2.5, 2.5, 2.5, 0.9, 0.88, 0.1)
        Halldoor = self.modeldict['Toonhall'].find('**/toonhall_door_origin')
        self.modelloadercopyto('Door3', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_round_ur', Halldoor, 0, -0.1, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door3'].setColor(0.88, 0.45, 0.38)
        self.modelloader('Schoolhouse', 'phase_4/models/modules/school_house.bam', render, 129.919, -138.445, 2.4997, -140, 0, 0, 1, 1, 1)
        Schoolsign = self.modeldict['Schoolhouse'].find('**/sign_origin')
        self.modelloadercopyto('Schoolsign', 'phase_4/models/props/signs_TTC.bam', 'TTC_sign3', Schoolsign, 1, -0.05, 3.7, 0, 0, 0, 1, 1, 1)
        self.textloader('Schooltext1', 'Schooltextnode1', 'Schooltextname1', 'Toontown', MickeyFont, Schoolsign, -2.5, -0.07, 4.8, 0, 0, 0, 1, 1, 1, 0.9, 0.88, 0.4)
        self.textloader('Schooltext2', 'Schooltextnode2', 'Schooltextname2', 'School House', MickeyFont, Schoolsign, -4.8, -0.07, 3, 0, 0, 0, 1.4, 1.4, 1.4, 0.9, 0.5, 0.1)
        Schooldoor = self.modeldict['Schoolhouse'].find('**/school_door_origin')
        self.modelloadercopyto('Door4', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_square_ul', Schooldoor, 0, -0.1, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door4'].setColor(1, 0.63, 0.38)
        self.modelloader('Bank', 'phase_4/models/modules/bank.bam', render, 57.1796, 38.6656, 4, 0, 0, 0, 1, 1, 1)
        Banksign = self.modeldict['Bank'].find('**/sign_origin')
        self.textloader('Banktext1', 'Banktextnode1', 'Banktextname1', 'Bank', MickeyFont, Banksign, -3.1, -0.2, -1, 0, 0, 0, 2.5, 2.5, 2.5, 0.9, 0.6, 0.1)
        Bankdoor = self.modeldict['Bank'].find('**/bank_door_origin')
        self.modelloadercopyto('Door5', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_round_ur', Bankdoor, 0, -0.1, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door5'].setColor(0.88, 0.45, 0.38)
        self.modelloader('Library', 'phase_4/models/modules/library.bam', render, 91.4475, -44.9255, 4, 180, 0, 0, 1, 1, 1)
        Librarysign = self.modeldict['Library'].find('**/sign_origin')
        self.modelloadercopyto('Librarysign', 'phase_4/models/props/signs_TTC.bam', 'TTC_sign3', Librarysign, 1.7, -0.05, 3.7, 0, 0, 0, 1, 1, 1)
        self.textloader('Librarytext1', 'Librarytextnode1', 'Librarytextname1', 'Toontown', MickeyFont, Librarysign, -1.5, -0.07, 4.8, 0, 0, 0, 1, 1, 1, 0.9, 0.88, 0.4)
        self.textloader('Librarytext2', 'Librarytextnode2', 'Librarytextname2', 'Library', MickeyFont, Librarysign, -2.8, -0.07, 3, 0, 0, 0, 1.9, 1.9, 1.9, 0.9, 0.5, 0.1)
        Librarydoor = self.modeldict['Library'].find('**/library_door_origin')
        self.modelloadercopyto('Door6', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_round_ur', Librarydoor, 0, 0, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door6'].setColor(0.88, 0.45, 0.38)
        self.modelloader('Gagshop', 'phase_4/models/modules/gagShop_TT.bam', render, -86.6848, -90.5693, 0.500015, 0, 0, 0, 1, 1, 1)
        Gagdoor = self.modeldict['Gagshop'].find('**/building_front')
        self.modelloadercopyto('Door7', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_square_ur', Gagdoor, 3, 0.1, 0, 180, 0, 0, 1, 1, 1)
        self.modeldict['Door7'].setColor(1, 0.63, 0.38)
        self.modelloader('GoofyTunnel', 'phase_4/models/modules/Speedway_Tunnel.bam', render, 20.9205, 172.683, 3.24925, -150, -0.083787, 0.0101321, 1, 1, 1)
        Goofysign = self.modeldict['GoofyTunnel'].find('**/sign_origin')
        self.textloader('Goofytext1', 'Goofytextnode1', 'Goofytextname1', 'Goofy', MickeyFont, Goofysign, -2, -0.07, 0.7, 0, 0, 0, 2.2, 2.2, 2.2, 0.1, 0.1, 0.7)
        self.textloader('Goofytext2', 'Goofytextnode2', 'Goofytextname2', 'Speed Way', MickeyFont, Goofysign, -6.1, -0.07, -2.8, 0, 0, 0, 2.6, 2.6, 2.6, 0.9, 0.5, 0.1)
        self.modelloader('FirstTunnel', 'phase_4/models/modules/safe_zone_tunnel_TT.bam', render, -239.67, 64.08, -6.18, -90, 0, 0, 1, 1, 1)
        SignOrigin1 = self.modeldict['FirstTunnel'].find('**/sign_origin')
        self.modelloader('Orangesign1', 'phase_3.5/models/props/tunnel_sign_orange.bam', SignOrigin1, 0, -0.05, 0, 0, 0, 0, 1.5, 1.5, 1.5)
        self.textloader('Tunnel1text1', 'Tunnel1textnode1', 'Tunnel1textname1', 'Loopy Lane', MickeyFont, SignOrigin1, -5.5, -0.07, -1.8, 0, 0, 0, 1.6, 1.6, 1.6, 0.0, 0.6, 0.1)
        self.textloader('Tunnel1text2', 'Tunnel1textnode2', 'Tunnel1textname2', 'Toontown Central', MickeyFont, SignOrigin1, -5.7, -0.7, -2.9, 0, 0, 0, 1, 1, 1, 0.0, 0.6, 0.0)
        self.modelloader('MickeyLogo1', 'phase_3.5/models/props/mickeySZ.bam', SignOrigin1, 0, -0.07, 2, 0, 0, 0, 4.5, 4.5, 4.5)
        self.modelloader('SecondTunnel', 'phase_4/models/modules/safe_zone_tunnel_TT.bam', render, -68.38, -202.64, -3.58, -31, 0, 0, 1, 1, 1)
        SignOrigin2 = self.modeldict['SecondTunnel'].find('**/sign_origin')
        self.textloader('Tunnel2text1', 'Tunnel2textnode1', 'Tunnel2textname1', 'Silly Street', MickeyFont, SignOrigin2, -5.9, -0.07, -1.8, 0, 0, 0, 1.6, 1.6, 1.6, 0.0, 0.6, 0.1)
        self.textloader('Tunnel2text2', 'Tunnel2textnode2', 'Tunnel2textname2', 'Toontown Central', MickeyFont, SignOrigin2, -5.7, -0.7, -2.9, 0, 0, 0, 1, 1, 1, 0.0, 0.6, 0.0)
        self.modelloader('Orangesign2', 'phase_3.5/models/props/tunnel_sign_orange.bam', SignOrigin2, 0, -0.05, 0, 0, 0, 0, 1.5, 1.5, 1.5)
        self.modelloader('MickeyLogo2', 'phase_3.5/models/props/mickeySZ.bam', SignOrigin2, 0, -0.07, 2, 0, 0, 0, 4.5, 4.5, 4.5)
        self.modelloader('ThirdTunnel', 'phase_4/models/modules/safe_zone_tunnel_TT.bam', render, 27.6402, 176.475, -6.18, 171, 0, 0, 1, 1, 1)
        SignOrigin3 = self.modeldict['ThirdTunnel'].find('**/sign_origin')
        self.textloader('Tunnel3text1', 'Tunnel3textnode1', 'Tunnel3textname1', 'Punchline Place', MickeyFont, SignOrigin3, -7.7, -0.07, -1.8, 0, 0, 0, 1.6, 1.6, 1.6, 0.0, 0.6, 0.1)
        self.textloader('Tunnel3text2', 'Tunnel3textnode2', 'Tunnel3textname2', 'Toontown Central', MickeyFont, SignOrigin3, -5.7, -0.7, -2.9, 0, 0, 0, 1, 1, 1, 0.0, 0.6, 0.0)
        self.modelloader('Orangesign3', 'phase_3.5/models/props/tunnel_sign_orange.bam', SignOrigin3, 0, -0.05, 0, 0, 0, 0, 1.5, 1.5, 1.5)
        self.modelloader('MickeyLogo3', 'phase_3.5/models/props/mickeySZ.bam', SignOrigin3, 0, -0.07, 2, 0, 0, 0, 4.5, 4.5, 4.5)
        self.modelloader('Fishingdock1', 'phase_4/models/props/piers_tt.bam', render, -63.5335, 41.648, -3.36708, 120, 0, 0, 1, 1, 1)
        self.modelloader('Fishingdock2', 'phase_4/models/props/piers_tt.bam', render, -90.2253, 42.5202, -3.3105, -135, 0, 0, 1, 1, 1)
        self.modelloader('Fishingdock3', 'phase_4/models/props/piers_tt.bam', render, -94.9218, 31.4153, -3.20083, -105, 0, 0, 1, 1, 1)
        self.modelloader('Fishingdock4', 'phase_4/models/props/piers_tt.bam', render, -77.5199, 46.9817, -3.28456, -180, 0, 0, 1, 1, 1)
        self.modelloader('DDSign1', 'phase_4/models/props/neighborhood_sign_DD.bam', render, -59.1768, 92.9836, 0.499824, -9, 0, 0, 1, 1, 1)
        self.modelloader('DDSign2', 'phase_4/models/props/neighborhood_sign_DD.bam', render, -33.749, 88.9499, 0.499825, 170, 0, 0, 1, 1, 1)
        self.modelloader('MMSign1', 'phase_4/models/props/neighborhood_sign_MM.bam', render, -143.503, -8.9528, 0.499987, 90, 0, 0, 1, 1, 1)
        self.modelloader('MMSign2', 'phase_4/models/props/neighborhood_sign_MM.bam', render, -143.242, 16.9541, 0.499977, -90, 0, 0, 1, 1, 1)
        self.modelloader('DGSign1', 'phase_4/models/props/neighborhood_sign_DG.bam', render, 21.3941, -144.665, 2.99998, -30, 0, 0, 1, 1, 1)
        self.modelloader('DGSign2', 'phase_4/models/props/neighborhood_sign_DG.bam', render, 44.1038, -157.906, 2.99998, 148, 0, 0, 1, 1, 1)
        self.modelloader('Gazebo', 'phase_4/models/modules/gazebo.bam', render, -60.44, -11.4, -2, -178, 0, 0, 1, 1, 1)
        self.modelloader('Fountain', 'phase_4/models/props/toontown_central_fountain.bam', render, 93.2057, -106.482, 2.50002, 0, 0, 0, 1, 1, 1)
        self.modelloader('Mickeyhorse', 'phase_4/models/props/mickey_on_horse.bam', render, 73.6829, 121.026, 2.49996, 0, 0, 0, 1, 1, 1)
        self.modelloader('FlowerPlant1', 'phase_3.5/models/props/big_planter.bam', render, 18.9496, -48.977, 4.95856, 135, 0, 0, 1, 1, 1)
        self.modelloader('FlowerPlant2', 'phase_3.5/models/props/big_planter.bam', render, 19.2327, 52.5553, 4.95837, -135, 0, 0, 1, 1, 1)
        self.modelloader('Fence1', 'phase_3.5/models/modules/wood_fence.bam', render, -148, -23, 0.5, 90, 0, 0, 1, 1, 1)
        self.modelloader('Fence2', 'phase_3.5/models/modules/wood_fence.bam', render, -147, -32.8, 0.5, 96, 0, 0, 1, 1, 1)
        self.modelloader('Fence3', 'phase_3.5/models/modules/wood_fence.bam', render, -144.1, -41.9, 0.5, 107, 0, 0, 1, 1, 1)
        self.modelloader('Fence4', 'phase_3.5/models/modules/wood_fence.bam', render, -95, -95.5, 0.5, 160, 0, 0, 1, 1, 1)
        self.modelloader('Fence5', 'phase_3.5/models/modules/wood_fence.bam', render, -104, -92.2, 0.5, 150, 0, 0, 1, 1, 1)
        self.modelloader('Fence6', 'phase_3.5/models/modules/wood_fence.bam', render, -112.5, -87.3, 0.5, 148, 0, 0, 1, 1, 1)
        self.modelloader('Fence7', 'phase_3.5/models/modules/wood_fence.bam', render, -140.73, -53, 0.5, 107, 0, 0, 1.16, 1, 1.0)
        self.modelloaderstreetlight('Streetlight1', 'phase_3.5/models/props/streetlight_TT.bam', render, -125, 60, 0.5, 1500, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight2', 'phase_3.5/models/props/streetlight_TT.bam', render, 58.8, 93.6, 3, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight3', 'phase_3.5/models/props/streetlight_TT.bam', render, 95, 93.6, 3, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight4', 'phase_3.5/models/props/streetlight_TT.bam', render, 134, -126, 3, -130, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight5', 'phase_3.5/models/props/streetlight_TT.bam', render, 108, -28, 4, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight6', 'phase_3.5/models/props/streetlight_TT.bam', render, 108, 32, 4, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight7', 'phase_3.5/models/props/streetlight_TT.bam', render, 32, 61, 4, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight8', 'phase_3.5/models/props/streetlight_TT.bam', render, 28, -57, 4, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight9', 'phase_3.5/models/props/streetlight_TT.bam', render, -101, -70, 0.5, 80, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight10', 'phase_3.5/models/props/streetlight_TT.bam', render, -129, -42.5, 0.5, 90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight11', 'phase_3.5/models/props/streetlight_TT.bam', render, 3.8, 118, 3, -110, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight12', 'phase_3.5/models/props/streetlight_TT.bam', render, 116, 146, 3, 145, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight13', 'phase_3.5/models/props/streetlight_TT.bam', render, 86, 164, 3, -95, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight14', 'phase_3.5/models/props/streetlight_TT.bam', render, 45.5, -88, 3, -2, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight15', 'phase_3.5/models/props/streetlight_TT.bam', render, 78.3, -88, 3, -2, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight16', 'phase_3.5/models/props/streetlight_TT.bam', render, 100, -157, 3, 30, 0, 0, 1, 1, 1)
        self.modelloadercopyto('Tree1', 'phase_3.5/models/props/trees.bam', 'prop_tree_large_no_box_ul', render, -80.9143, 79.7948, 0.2, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree2', 'phase_3.5/models/props/trees.bam', 'prop_tree_large_no_box_ul', render, -26.1169, 73.7975, 0.2, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree3', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 7.14367, 100.346, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree4', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 55.8308, 153.977, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree5', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 102.359, 81.1646, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree6', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 114.09, 57.3141, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree7', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 143.598, 110.178, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree8', 'phase_3.5/models/props/trees.bam', 'prop_tree_large_no_box_ul', render, -128.41, 32.9562, 0.2, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree9', 'phase_3.5/models/props/trees.bam', 'prop_tree_large_no_box_ul', render, -128.708, -23.9096, 0.2, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree10', 'phase_3.5/models/props/trees.bam', 'prop_tree_large_no_box_ul', render, -52.4323, -73.2793, 0.2, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree11', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 7.00708, -99.2181, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree12', 'phase_3.5/models/props/trees.bam', 'prop_tree_small_no_box_ul', render, 96.5467, -145.522, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree13', 'phase_3.5/models/props/trees.bam', 'prop_tree_small_no_box_ul', render, 119.57, -127.05, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree14', 'phase_3.5/models/props/trees.bam', 'prop_tree_small_no_box_ul', render, 128.064, -60.4145, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree15', 'phase_3.5/models/props/trees.bam', 'prop_tree_small_no_box_ul', render, 121.146, -45.0892, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree16', 'phase_3.5/models/props/trees.bam', 'prop_tree_small_no_box_ul', render, 113.503, -57.8055, 2.725, 1, 1, 1, 1, 1, 1)

    def modelloader(self, nodename, modelpath, renderparent, x, y, z, h, p, r, scale1, scale2, scale3):
        self.modeldict[nodename] = loader.loadModel(modelpath)
        self.modeldict[nodename].reparentTo(renderparent)
        self.modeldict[nodename].setPos(x, y, z)
        self.modeldict[nodename].setHpr(h, p, r)
        self.modeldict[nodename].setScale(scale1, scale2, scale3)

    def modelloadercopyto(self, nodename, modelpath, findmodel, renderparent, x, y, z, h, p, r, scale1, scale2, scale3):
        self.modeldict[nodename] = loader.loadModel(modelpath)
        self.modeldict[nodename] = self.modeldict[nodename].find('**/' + findmodel).copyTo(renderparent)
        self.modeldict[nodename].setPos(x, y, z)
        self.modeldict[nodename].setHpr(h, p, r)
        self.modeldict[nodename].setScale(scale1, scale2, scale3)

    def modelloaderanimate(self, nodename, modelpath, animatepath, renderparent, x, y, z, h, p, r, scale1, scale2, scale3, animation):
        self.modeldict[nodename] = Actor(modelpath, {animation: animatepath})
        self.modeldict[nodename].reparentTo(renderparent)
        self.modeldict[nodename].setPos(x, y, z)
        self.modeldict[nodename].setHpr(h, p, r)
        self.modeldict[nodename].setScale(scale1, scale2, scale3)
        self.modeldict[nodename].loop(animation)

    def textloader(self, nodename, Textnodename, Textname, Textdata, Fonttype, renderparent, x, y, z, h, p, r, scale1, scale2, scale3, color1, color2, color3):
        Textname = TextNode(Textnodename)
        Textname.setText(Textdata)
        Textname.setFont(Fonttype)
        self.modeldict[nodename] = renderparent.attachNewNode(Textname)
        self.modeldict[nodename].setPos(x, y, z)
        self.modeldict[nodename].setHpr(h, p, r)
        self.modeldict[nodename].setScale(scale1, scale2, scale3)
        self.modeldict[nodename].setColor(color1, color2, color3)

    def modelloaderstreetlight(self, nodename, modelpath, renderparent, x, y, z, h, p, r, scale1, scale2, scale3):
        self.modeldict[nodename] = loader.loadModel(modelpath)
        self.modeldict[nodename].reparentTo(renderparent)
        self.modeldict[nodename].setPos(x, y, z)
        self.modeldict[nodename].setHpr(h, p, r)
        self.modeldict[nodename].setScale(scale1, scale2, scale3)
        self.modeldict[nodename].find('**/prop_post_light_base').hide()
        self.modeldict[nodename].find('**/p1').hide()
        self.modeldict[nodename].find('**/prop_post_one_light').hide()
        self.modeldict[nodename].find('**/p13').hide()

BTFont = loader.loadFont('phase_3/models/fonts/MickeyFont.bam')
bk_text = ' '
textObject = OnscreenText(text=bk_text, pos=(0.95, -0.95), scale=0.07, fg=(1,
 0.5,
 0.5,
 1), align=TextNode.ACenter, mayChange=1)
textObject.setFont(BTFont)

def setText(textEntered):
    textObject.setText(textEntered)
    if b:
        b.hide()
        ImgBtn2.show()

def clearText():
    if b:
        b.enterText('')

def openChatGui():
    if b:
        b.show()
        ImgBtn2.hide()

chatGui = loader.loadModel('phase_3.5/models/gui/chat_input_gui.bam')
b = DirectEntry(text='', scale=0.05, command=setText, initialText='Type Something', numLines=3, focus=1, focusInCommand=clearText)
b.hide()
chatGui = loader.loadModel('phase_3.5/models/gui/chat_input_gui.bam')
chatGui = loader.loadModel('phase_3.5/models/gui/chat_input_gui.bam')
ImgBtn2 = DirectButton(frameSize=None, text=' ', image=(chatGui.find('**/ChtBx_ChtBtn_UP'), chatGui.find('**/ChtBx_ChtBtn_DN'), chatGui.find('**/ChtBx_ChtBtn_RLVR')), relief=None, command=openChatGui, text_pos=(2, -0.325), geom=None, pad=(0.01, 0.01), suppressKeys=0, pos=(-1.21, -1, 0.9), text_scale=1, borderWidth=(0.015, 0.01))
b.setPos(-1.21, -2, 5)
chatGui = loader.loadModel('phase_3.5/models/gui/chat_input_gui.bam')
ImgBtn2 = DirectButton(frameSize=None, text=' ', image=(chatGui.find('**/ChtBx_ChtBtn_UP'), chatGui.find('**/ChtBx_ChtBtn_DN'), chatGui.find('**/ChtBx_ChtBtn_RLVR')), relief=None, command=openChatGui, text_pos=(2, -0.325), geom=None, pad=(0.01, 0.01), suppressKeys=0, pos=(-1.1, -1, 0.9), text_scale=0.06, color=(0, 1, 0), borderWidth=(0.015, 0.01))
b.setPos(-1.21, -2, 0.75)
Font = loader.loadFont('phase_3/models/fonts/Courier.bam')
tag = OnscreenText(scale=0.5, text='Smirky Superchomp', bg=(0.9,
 0.9,
 0.9,
 0.3), fg=(0.35,
 0.35,
 0.95,
 1), decal=True)
tag.wrtReparentTo(DuckBody)
tag.setBillboardAxis()
tag.setPos(0, 0)
tag.setDepthTest(True)
tag.setDepthWrite(True)
tag.reparentTo(DuckBody)
tag.setZ(tag, DuckBody.find('**/__Actor_head').getZ(DuckBody) + -1)
tag.reparentTo(DuckBody.find('**/def_head'))
tag.setFont(BTFont)
fist = loader.loadModel('phase_3.5/models/gui/tt_m_gui_gm_toonResistance_fist.bam')
fist.reparentTo(DuckBody.find('**/def_head'))
fist.setPos(0, 0, 0)
fist.setScale(2.3)
fist.find('**/gmPartyHat').remove()
ttHatSpin = fist.find('**/fistIcon').hprInterval(3, Vec3(360, 0, 0))
ttHatSpin.loop()
fedora = loader.loadModel('phase_4/models/accessories/tt_m_chr_avt_acc_hat_fedora.bam')
fedora.reparentTo(DuckBody.find('**/def_head'))
fedora.setScale(0.35)
fedora.setZ(0.75)
fedora.setH(180)
nerdglasses = loader.loadModel('phase_4/models/accessories/tt_m_chr_avt_acc_msk_squareRims.bam')
nerdglasses.reparentTo(DuckBody.find('**/def_head'))
nerdglasses.setH(180)
nerdglasses.setScale(0.45)
nerdglasses.setZ(0.2)
nerdglasses.setY(0.05)
CS1 = loader.loadModel('phase_5/models/modules/TT_A2.bam')
CS1.reparentTo(render)
CS1.setH(138.37)
CS1.setX(-109.07)
CS1.setY(-92.27)
CS2 = loader.loadModel('phase_5/models/modules/TT_A3.bam')
CS2.reparentTo(render)
CS2.setH(104.93)
CS2.setX(-132.65)
CS2.setY(-74.96)

def TP1():
    DuckBody.setZ(500.89)
    DuckBody.setY(59.6964)
    DuckBody.setX(-1.00264)

ButtonImage = loader.loadModel('phase_3/models/gui/quit_button.bam')
ImgBtn11 = DirectButton(frameSize=None, text='SpeedWay', image=(ButtonImage.find('**/QuitBtn_UP'), ButtonImage.find('**/QuitBtn_DN'), ButtonImage.find('**/QuitBtn_RLVR')), relief=None, command=TP1, text_pos=(0, -0.015), geom=None, pad=(0.01, 0.01), suppressKeys=0, pos=(-0.05, 0, 0.95), text_scale=0.059, borderWidth=(0.13, 0.01), scale=0.7, color=(0, 1, 0))
environ = loader.loadModel('phase_6/models/karting/GasolineAlley_TT.bam')
environ.reparentTo(render)
environ.setZ(500)
tunnel = loader.loadModel('phase_4/models/modules/safe_zone_tunnel_TT.bam')
tunnel.reparentTo(render)
tunnel.setPos(60, 175, 493)
tunnel.setHpr(180, 0, 0)
tunnel.setScale(1)
tunnelsign = loader.loadModel('phase_3.5/models/props/tunnel_sign_orange.bam')
tunnelsign.reparentTo(tunnel)
tunnelsign.setPos(60, 95.01, 523.7)
tunnelsign.setHpr(180, 0, 0)
tunnelsign.setScale(1.6)
SZsign = loader.loadModel('phase_4/models/props/goofySZ.bam')
SZsign.reparentTo(tunnel)
SZsign.setPos(60, 95.025, 523.7)
SZsign.setHpr(180, 0, 0)
SZsign.setScale(4)
kartshop = loader.loadModel('phase_6/models/karting/kartShop.bam')
kartshop.reparentTo(render)
kartshop.setPos(0, 10, 500)
scoreboard = loader.loadModel('phase_6/models/karting/tt_m_ara_gfs_leaderBoardCrashed.bam')
scoreboard.reparentTo(render)
scoreboard.setPos(1, -111, 500)
scoreboard.setHpr(180, 0, 0)
wrench = loader.loadModel('phase_6/models/karting/KartArea_WrenchJack.bam')
wrench.reparentTo(render)
wrench.setPos(-33, 5, 500)
wrench.setHpr(180, 0, 0)
tires = loader.loadModel('phase_6/models/karting/KartArea_Tires.bam')
tires.reparentTo(render)
tires.setPos(33, 5, 500)
trees1 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees1.reparentTo(render)
trees1.setPos(-13, 58, 499.7)
trees1.setScale(12)
trees2 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees2.reparentTo(render)
trees2.setPos(13, 58, 499.7)
trees2.setScale(12)
trees3 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees3.reparentTo(render)
trees3.setPos(-13, -35, 499.7)
trees3.setScale(12)
trees4 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees4.reparentTo(render)
trees4.setPos(13, -35, 499.7)
trees4.setScale(12)
trees5 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees5.reparentTo(render)
trees5.setPos(-10, -76, 499.7)
trees5.setScale(12)
trees6 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees6.reparentTo(render)
trees6.setPos(10, -76, 499.7)
trees6.setScale(12)
light1 = loader.loadModel('phase_6/models/karting/GoofyStadium_Lamppost_Base1.bam')
light1.reparentTo(render)
light1.setPos(-10, -52, 499.3)
light1.setScale(14)
light2 = loader.loadModel('phase_6/models/karting/GoofyStadium_Lamppost_Base1.bam')
light2.reparentTo(render)
light2.setPos(10, -52, 499.3)
light2.setScale(14)
box = loader.loadModel('phase_6/models/karting/GoofyStadium_Mailbox.bam')
box.reparentTo(render)
box.setPos(16, -50, 500)
box.setHpr(210, 0, 0)
box.setScale(10)
flag1 = loader.loadModel('phase_6/models/karting/flag.bam')
flag1.reparentTo(render)
flag1.setPos(-18, 6, 499.8)
flag2 = loader.loadModel('phase_6/models/karting/flag.bam')
flag2.reparentTo(render)
flag2.setPos(18, 6, 499.8)
sign = loader.loadModel('phase_6/models/karting/KartShowBlockSign.bam')
sign.reparentTo(render)
sign.setPos(-16, -50, 500)
sign.setHpr(-120, 0, 0)
sign.setScale(26)
announcer1 = loader.loadModel('phase_6/models/karting/announcer.bam')
announcer1.reparentTo(render)
announcer1.setPos(25, -150, 499.3)
announcer1.setHpr(-140, 0, 0)
announcer2 = loader.loadModel('phase_6/models/karting/announcer.bam')
announcer2.reparentTo(render)
announcer2.setPos(-26, -149, 499.3)
announcer2.setHpr(-212, 0, 0)
announcer3 = loader.loadModel('phase_6/models/karting/announcer.bam')
announcer3.reparentTo(render)
announcer3.setPos(-38, -135, 499.3)
announcer3.setHpr(-212, 0, 0)
announcer4 = loader.loadModel('phase_6/models/karting/announcer.bam')
announcer4.reparentTo(render)
announcer4.setPos(37, -137.5, 499.3)
announcer4.setHpr(-140, 0, 0)
cone1 = loader.loadModel('phase_6/models/karting/cone.bam')
cone1.reparentTo(render)
cone1.setPos(13, -4, 499.7)
cone2 = loader.loadModel('phase_6/models/karting/cone.bam')
cone2.reparentTo(render)
cone2.setPos(13, 20, 499.7)
cone3 = loader.loadModel('phase_6/models/karting/cone.bam')
cone3.reparentTo(render)
cone3.setPos(-14, 18, 499.7)
cone4 = loader.loadModel('phase_6/models/karting/cone.bam')
cone4.reparentTo(render)
cone4.setPos(-14, -3, 499.7)
cone5 = loader.loadModel('phase_6/models/karting/cone.bam')
cone5.reparentTo(render)
cone5.setPos(-23, 9, 499.7)
cone6 = loader.loadModel('phase_6/models/karting/cone.bam')
cone6.reparentTo(render)
cone6.setPos(45, -138, 499.4)
cone7 = loader.loadModel('phase_6/models/karting/cone.bam')
cone7.reparentTo(render)
cone7.setPos(25, -109, 500)
cone8 = loader.loadModel('phase_6/models/karting/cone.bam')
cone8.reparentTo(render)
cone8.setPos(24, -111, 500)
cone8.setHpr(45, 0, 0)
cone9 = loader.loadModel('phase_6/models/karting/cone.bam')
cone9.reparentTo(render)
cone9.setPos(75, -106, 500)
cone9.setHpr(0, 0, -120)
cone10 = loader.loadModel('phase_6/models/karting/cone.bam')
cone10.reparentTo(render)
cone10.setPos(76.5, -107.5, 500)
cone10.setHpr(0, 120, 0)
cone11 = loader.loadModel('phase_6/models/karting/cone.bam')
cone11.reparentTo(render)
cone11.setPos(26, -154, 499.3)
cone11.setHpr(42, 0, 0)
cone12 = loader.loadModel('phase_6/models/karting/cone.bam')
cone12.reparentTo(render)
cone12.setPos(1, -187, 501.22)
cone12.setHpr(42, 0, 0)
krate1 = loader.loadModel('phase_6/models/karting/krate.bam')
krate1.reparentTo(render)
krate1.setPos(1, -187, 499.3)
krate1.setScale(1.2)
krate2 = loader.loadModel('phase_6/models/karting/krate.bam')
krate2.reparentTo(render)
krate2.setPos(-48, -115, 499.3)
krate2.setScale(1.2)
krate3 = loader.loadModel('phase_6/models/karting/krate.bam')
krate3.reparentTo(render)
krate3.setPos(-50, -113, 499.3)
krate3.setHpr(45, 0, 0)
krate3.setScale(1.2)
krate4 = loader.loadModel('phase_6/models/karting/krate.bam')
krate4.reparentTo(render)
krate4.setPos(-49, -114, 501.22)
krate4.setHpr(60, 0, 0)
krate4.setScale(1.2)

def TP2():
    DuckBody.setZ(0)
    DuckBody.setX(0)
    DuckBody.setY(0)

ButtonImage = loader.loadModel('phase_3/models/gui/quit_button.bam')
ImgBtn11 = DirectButton(frameSize=None, text='TTC', image=(ButtonImage.find('**/QuitBtn_UP'), ButtonImage.find('**/QuitBtn_DN'), ButtonImage.find('**/QuitBtn_RLVR')), relief=None, command=TP2, text_pos=(0, -0.015), geom=None, pad=(0.01, 0.01), suppressKeys=0, pos=(1, 0, 0.95), text_scale=0.059, borderWidth=(0.13, 0.01), scale=0.7, color=(0, 1, 0))
lord = Actor('phase_3/models/char/mickey-1200.bam', {'walk': 'phase_3/models/char/mickey-walk.bam'})
lord.reparentTo(render)
lord.loop('walk')
lord.setX(106.58)
lord.setY(-1.37)
lord.setZ(4.46)
lord.setH(104.62)
cs = CollisionSphere(0, 0, 1, 3)
cnodePath = lord.attachNewNode(CollisionNode('cnode'))
cnodePath.node().addSolid(cs)
pandaPosInterval1 = lord.posInterval(3, Point3(96.3312, 0.553801, 4.025), startPos=Point3(96.3312, 0.553801, 4.025))
pandaHprInterval1 = lord.hprInterval(3, Point3(96.3312, 0.553801, 4.025), startHpr=Point3(96.3312, 0.553801, 4.025))
pandaPosInterval2 = lord.posInterval(3, Point3(54.1032, 10.1371, 4.025), startPos=Point3(96.3312, 0.553801, 4.025))
pandaHprInterval2 = lord.hprInterval(3, Point3(172.798, 0, 0), startHpr=Point3(96.3312, 0.553801, 4.025))
pandaPosInterval3 = lord.posInterval(3, Point3(62.9905, -21.4791, 6.05112), startPos=Point3(54.1032, 10.1371, 4.025))
pandaHprInterval3 = lord.hprInterval(3, Point3(438.492, 0, 0), startHpr=Point3(172.798, 0, 0))
lord.pandaPace = Sequence(pandaPosInterval1, pandaHprInterval1, pandaPosInterval2, pandaHprInterval2, pandaPosInterval3, pandaHprInterval3)
lord.pandaPace.loop()
environ = EnvironmentTTC()
base.taskMgr.add(updateOnScreenDebug, 'UpdateOSD')
tag2 = OnscreenText(scale=2, text='Mickey', bg=(0.9,
 0.9,
 0.9,
 0.3), fg=(0.35,
 0.35,
 0.95,
 1), decal=True)
tag2.wrtReparentTo(lord)
tag2.setBillboardAxis()
tag2.setPos(0, 0)
tag2.setDepthTest(True)
tag2.setDepthWrite(True)
tag2.reparentTo(lord)
tag2.setZ(tag, lord.find('**/joint_pupilL').getZ(lord) + 1)
tag2.reparentTo(lord.find('**/joint_pupilL'))
tag2.setFont(BTFont)
tag2.setColor(1, 0.1, 0.1, 1.0)
title.destroy()

base.oobe()
run()


from ..h2o import random_forest
from .estimator_base import H2OEstimator

class H2ORandomForestEstimator(H2OEstimator):
  def __init__(self,mtries=None,sample_rate=None,build_tree_one_node=None,ntrees=None,
               max_depth=None,min_rows=None,nbins=None,nbins_cats=None,
               binomial_double_trees=None,balance_classes=None,max_after_balance_size=None,
               seed=None,offset_column=None,weights_column=None):
    super(H2ORandomForestEstimator, self).__init__()
    self.parms = locals()
    self.parms = {k:v for k,v in self.parms.iteritems() if k!="self"}
    self._estimator_type="regressor"

  def fit(self,X,y=None,**params):
    if y is not None:
      if y.isfactor(): self._estimator_type="classifier"
    self.__dict__=random_forest(x=X,y=y,**self.parms).__dict__.copy()


import json
import os
import cv2
import numpy as np
import numpy.matlib
import matplotlib.pyplot as plt
import matplotlib.patches as patches

import matplotlib.animation as animation

# change IDs to your IDs.
ID1 = '206299463'
ID2 = '312497084'

ID = "HW3_{0}_{1}".format(ID1, ID2)
RESULTS = 'results'
os.makedirs(RESULTS, exist_ok=True)
IMAGE_DIR_PATH = "Images"

# SET NUMBER OF PARTICLES
N = 100

# Initial Settings
s_initial = [297,    # x center
             139,    # y center
              16,    # half width
              43,    # half height
               0,    # velocity x
               0]    # velocity y

# state index constants for readability becuase I keep forgetting
X_ind = 0
Y_ind = 1
W_ind = 2
H_ind = 3
VX_ind = 4
VY_ind = 5

WIDTH = 576
HEIGHT = 352

# set this to True if you want to generate a video of the tracking process
GENERATE_VIDEO = False

def predict_particles(s_prior: np.ndarray) -> np.ndarray:
    """Progress the prior state with time and add noise.

    Note that we explicitly did not tell you how to add the noise.
    We allow additional manipulations to the state if you think these are necessary.

    Args:
        s_prior: np.ndarray. The prior state.
    Return:
        state_drifted: np.ndarray. The prior state after drift (applying the motion model) and adding the noise.
    """

    ''' A little about our motion model assumptions:
     the input video is of a running human, mostly on a horizontal plane; for an average running pace of 2~3 m/s,
     a running human moves (horizontally) an average of 0.1 meters between frames.
     We estimated the FPS of the input video to be ~25[fps] by by observing the video at different frame rates
     and converging on what felt like natural movement; we then estimate the pixel/meter ratio to be ~65
     by measuring the human's height in pixels (110[px]) and dividing it by an average human's height (1.7[m]),
     as well as assuming same px/m ratio for horizontal and vertical directions.
     Finally, we end up with a possible range 6~7 pixels horizontal displacement between frames;
     as for vertical displacement, assuming a constant height human (most likely), we assume a maximum of
     ~3px vertical displacement between frames, for the scenario that the human meets a sudden slope.'''

    # Progress the state with time
    s_prior = s_prior.astype(float)
    state_drifted = np.copy(s_prior)

    # update current state's positions according to the prior's velocity
    state_drifted[[X_ind, Y_ind]] += s_prior[[VX_ind, VY_ind]]

    # the bounding box might drift out of the frame if the
    # tracked object is moving towards the frame's edges
    state_drifted[[X_ind, Y_ind]] = np.clip(state_drifted[[X_ind, Y_ind]].T, [0, 0], [WIDTH-1, HEIGHT-1]).T

    # estimating uniform noise: x,y limits according typical human velocities,
    # vx, vy limits according to typical human acceleration - a human might start/stop moving
    # which will be reflected in abrupt changes in velocity
    x_lim = 7
    y_lim = 3
    vx_lim = 4
    vy_lim = 2
    h_lim = w_lim = 0 # no changes in width/height
    lims = np.vstack(np.array([x_lim, y_lim, w_lim, h_lim, vx_lim, vy_lim]))

    noise = np.random.uniform(-1*lims, lims, size=state_drifted.shape)
    state_drifted += noise

    # keep velocities within reasonable limits as described in the motion model
    state_drifted[[VX_ind, VY_ind]] = np.clip(state_drifted[[VX_ind, VY_ind]].T, [-1.2*vx_lim, -0.8*vy_lim], [1.2*vx_lim, 0.8*vy_lim]).T
    return state_drifted

def compute_normalized_histogram(image: np.ndarray, state: np.ndarray) -> np.ndarray:
    """Compute the normalized histogram using the state parameters.

    Args:
        image: np.ndarray. The image we want to crop the rectangle from.
        state: np.ndarray. State candidate.

    Return:
        hist: np.ndarray. histogram of quantized colors.
    """
    x, y, w, h, _, _ = state.astype(int)
    patch = image[y-h:y+h, x-w:x+w]
    H = cv2.calcHist([patch], [0, 1, 2], None, [16, 16, 16], [0, 256, 0, 256, 0, 256])
    H /= H.sum() # normalize histogram
    return H.flatten()

def sample_particles(previous_state: np.ndarray, cdf: np.ndarray) -> np.ndarray:
    """Sample particles from the previous state according to the cdf.

    If additional processing to the returned state is needed - feel free to do it.

    Args:
        previous_state: np.ndarray. previous state, shape: (6, N)
        cdf: np.ndarray. cummulative distribution function: (N, )

    Return:
        s_next: np.ndarray. Sampled particles. shape: (6, N)
    """
    rs = np.random.random(size=cdf.shape)
    diffs = cdf - np.vstack(rs) # The resultant matrix D(iffs) holds: Dij = cdf[j]-rs[i]
    diffs[diffs <= 0] = np.inf   # I eliminate all the negative values in diffs from the comparison
    new_indices = diffs.argmin(axis=1) # find the minimum value in each column, that is the new index of the particle
    s_next = previous_state[:, new_indices]

    # purposefully not calculating velocity after resampling
    # instead, rely on the motion model described in predict_particles
    # to estimate the velocity

    return s_next

def bhattacharyya_distance(p: np.ndarray, q: np.ndarray) -> float:
    """Calculate Bhattacharyya Distance between two histograms p and q.

    Args:
        p: np.ndarray. first histogram.
        q: np.ndarray. second histogram.

    Return:
        distance: float. The Bhattacharyya Distance.
    """
    return np.exp(20*np.sqrt(p*q).sum())

def create_image_with_boundingbox(image: np.ndarray,
                                  mean_bbox: tuple,
                                  max_bbox: tuple,
                                  current_bbox: tuple
                                  ) -> np.ndarray:
    """Create an image with the bounding box and the ID.
       I used this function to create a video of the entire tracking process,
       this proved very helpful in estimating the best tuning parameters for
       the tracking algorithm, as well as include tweaks in the algorithm itself.
       To view the video, set the "GENERATE_VIDEO" variable to True at the top of the file

    """
    image_with_bbox = image.copy()

    # max bbox in red
    x, y, w, h = [int(round(i)) for i in max_bbox]
    image_with_bbox = cv2.rectangle(image_with_bbox, (x-w, y-h), (x+w, y+h), (0, 0, 255), 2)

    # mean bbox in green
    x, y, w, h = [int(round(i)) for i in mean_bbox]
    image_with_bbox = cv2.rectangle(image_with_bbox, (x-w, y-h), (x+w, y+h), (0, 255, 0), 2)

    # current bbox in blue
    x, y, w, h = [int(round(i)) for i in current_bbox]
    image_with_bbox = cv2.rectangle(image_with_bbox, (x-w, y-h), (x+w, y+h), (255, 0, 0), 2)

    return image_with_bbox

def show_particles(image: np.ndarray, state: np.ndarray, W: np.ndarray, frame_index: int, ID: str,
                  frame_index_to_mean_state: dict, frame_index_to_max_state: dict,
                  ) -> tuple:
    fig, ax = plt.subplots(1)
    image = image[:,:,::-1]
    plt.imshow(image)
    plt.title(ID + " - Frame number = " + str(frame_index))

    # Avg particle box
    avg_state = np.average(state, axis=1, weights=W)
    (x_avg, y_avg, w_avg, h_avg, _, _) = avg_state
    rect = patches.Rectangle((x_avg-w_avg, y_avg-h_avg), 2*w_avg, 2*h_avg, linewidth=2, edgecolor='g', facecolor='none')
    ax.add_patch(rect)

    # calculate Max particle box
    max_state = state[:, np.argmax(W)]
    (x_max, y_max, w_max, h_max, _, _) = max_state
    rect = patches.Rectangle((x_max-w_max, y_max-h_max), 2*w_max, 2*h_max, linewidth=2, edgecolor='r', facecolor='none')
    ax.add_patch(rect)
    plt.show(block=False)

    fig.savefig(os.path.join(RESULTS, ID + "-" + str(frame_index) + ".png"))
    frame_index_to_mean_state[frame_index] = [float(x) for x in [x_avg, y_avg, w_avg, h_avg]]
    frame_index_to_max_state[frame_index] = [float(x) for x in [x_max, y_max, w_max, h_max]]
    return frame_index_to_mean_state, frame_index_to_max_state

def main():
    state_at_first_frame = np.matlib.repmat(s_initial, N, 1).T
    S = predict_particles(state_at_first_frame)

    # LOAD FIRST IMAGE
    image = cv2.imread(os.path.join(IMAGE_DIR_PATH, "001.png"))

    # COMPUTE NORMALIZED HISTOGRAM
    q = compute_normalized_histogram(image, np.array(s_initial))

    # COMPUTE NORMALIZED WEIGHTS (W) AND PREDICTOR CDFS (C)
    weights = np.array([bhattacharyya_distance(compute_normalized_histogram(image, s), q) for s in S.T])
    weights /= weights.sum()

    # Initialize the variable W with the computed weights
    W = weights

    # COMPUTE CDF
    cdf = np.cumsum(weights)

    images_processed = 1

    # MAIN TRACKING LOOP
    image_name_list = os.listdir(IMAGE_DIR_PATH)
    image_name_list.sort()
    images_paths = [os.path.join(IMAGE_DIR_PATH, image_name) for image_name in image_name_list]
    frame_index_to_avg_state = {}
    frame_index_to_max_state = {}

    if GENERATE_VIDEO:
        dimensions = image.shape[:2][::-1]
        slowed_down_vw = cv2.VideoWriter(os.path.join(RESULTS, "slowed_down_video.avi"),
                             fourcc=cv2.VideoWriter_fourcc(*'XVID'),
                             fps=10,
                             frameSize=dimensions,
                             isColor=True)

        real_time_vw = cv2.VideoWriter(os.path.join(RESULTS, "normal_speed_video.avi"),
                             fourcc=cv2.VideoWriter_fourcc(*'XVID'),
                             fps=25,
                             frameSize=dimensions,
                             isColor=True)

        mean_bbox = s_initial[:4]
        max_bbox = s_initial[:4]

    for image_path in images_paths[1:]:

        S_prev = S

        # LOAD NEW IMAGE FRAME
        current_image = cv2.imread(image_path)

        # SAMPLE THE CURRENT PARTICLE FILTERS
        S_next_tag = sample_particles(S_prev, cdf)

        # PREDICT THE NEXT PARTICLE FILTERS (YOU MAY ADD NOISE)
        S = predict_particles(S_next_tag)

        # COMPUTE NORMALIZED WEIGHTS (W) AND PREDICTOR CDFS (C)
        # YOU NEED TO FILL THIS PART WITH CODE:
        weights = np.array([bhattacharyya_distance(compute_normalized_histogram(current_image, s), q) for s in S.T])
        weights /= weights.sum()
        W = weights

        # COMPUTE CDF
        cdf = np.cumsum(weights)

        # CREATE DETECTOR PLOTS
        images_processed += 1
        if 0 == images_processed%10:
            frame_index_to_avg_state, frame_index_to_max_state = show_particles(
                current_image, S, W, images_processed, ID, frame_index_to_avg_state, frame_index_to_max_state)
            if GENERATE_VIDEO:
                mean_bbox = frame_index_to_avg_state[images_processed]
                max_bbox = frame_index_to_max_state[images_processed]

        if GENERATE_VIDEO:
            current_frame_bbox = np.average(S[[X_ind, Y_ind, W_ind, H_ind]], axis=1, weights=W)
            bounded_frame = create_image_with_boundingbox(current_image, mean_bbox, max_bbox, current_frame_bbox)
            slowed_down_vw.write(bounded_frame)
            real_time_vw.write(bounded_frame)

    if GENERATE_VIDEO:
        slowed_down_vw.release()
        real_time_vw.release()

    with open(os.path.join(RESULTS, 'frame_index_to_avg_state.json'), 'w') as f:
        json.dump(frame_index_to_avg_state, f, indent=4)
    with open(os.path.join(RESULTS, 'frame_index_to_max_state.json'), 'w') as f:
        json.dump(frame_index_to_max_state, f, indent=4)

if __name__ == "__main__":
    main()


def add_piece(music_list, song, information):
    new_singer = information[2]
    new_key = information[3]
    if song not in music_list:
        music_list[song] = {'composer': new_singer, 'key': new_key}
        print(f'{song} by {new_singer} in {new_key} added to the collection!')
    else:
        print(f"{song} is already in the collection!")
    return music_list

def remove_piece(music_list, song):
    if song not in music_list:
        print(f"Invalid operation! {song} does not exist in the collection.")
    else:
        del music_list[song]
        print(f"Successfully removed {song}!")
    return music_list

def change_key(music_list, song, information):
    new_key = information[2]
    if song not in music_list:
        print(f"Invalid operation! {song} does not exist in the collection.")
    else:
        music_list[song]['key'] = new_key
        print(f"Changed the key of {song} to {new_key}!")
    return music_list

discography = {}

number_of_pieces = int(input())

for song in range(number_of_pieces):
    piece, composer, key = input().split('|')

    if piece not in discography:
        discography[piece] = {'composer': composer, 'key': key}

while True:
    input_data = input()
    if input_data == 'Stop':
        break

    data = input_data.split('|')
    command = data[0]
    piece = data[1]

    if command == 'Add':
        discography = add_piece(discography, piece, data)
    elif command == 'Remove':
        discography = remove_piece(discography, piece)
    elif command == 'ChangeKey':
        discography = change_key(discography, piece, data)

for piece, info in discography.items():
    composer = info['composer']
    key = info['key']
    print(f"{piece} -> Composer: {composer}, Key: {key}")

#################################### TASK CONDITION ############################
"""
                          Problem 3 - The Pianist
Problem for exam preparation for the Programming Fundamentals Course @SoftUni.
Submit your solutions in the SoftUni judge system at https://judge.softuni.org/Contests/Practice/Index/2525#2.

You are a pianist, and you like to keep a list of your favorite piano pieces.
Create a program to help you organize it and add, change, remove pieces from it!
On the first line of the standard input, you will receive an integer n – the number
of pieces you will initially have. On the next n lines, the pieces themselves will
follow with their composer and key, separated by "|" in the following format: "{piece}|{composer}|{key}".
Then, you will be receiving different commands, each on a new line, separated by "|",
 until the "Stop" command is given:
•	"Add|{piece}|{composer}|{key}":
o	You need to add the given piece with the information about it to the other pieces and print:
"{piece} by {composer} in {key} added to the collection!"
o	If the piece is already in the collection, print:
"{piece} is already in the collection!"
•	"Remove|{piece}":
o	If the piece is in the collection, remove it and print:
"Successfully removed {piece}!"
o	Otherwise, print:
"Invalid operation! {piece} does not exist in the collection."
•	"ChangeKey|{piece}|{new key}":
o	If the piece is in the collection, change its key with the given one and print:
"Changed the key of {piece} to {new key}!"
o	Otherwise, print:
"Invalid operation! {piece} does not exist in the collection."
Upon receiving the "Stop" command, you need to print all pieces in your collection in the following format:
"{Piece} -> Composer: {composer}, Key: {key}"
Input/Constraints
•	You will receive a single integer at first – the initial number of pieces in the collection
•	For each piece, you will receive a single line of text with information about it.
•	Then you will receive multiple commands in the way described above until the command "Stop".
Output
•	All the output messages with the appropriate formats are described in the problem description.

____________________________________________________________________________________________
Example_01

Input
3
Fur Elise|Beethoven|A Minor
Moonlight Sonata|Beethoven|C# Minor
Clair de Lune|Debussy|C# Minor
Add|Sonata No.2|Chopin|B Minor
Add|Hungarian Rhapsody No.2|Liszt|C# Minor
Add|Fur Elise|Beethoven|C# Minor
Remove|Clair de Lune
ChangeKey|Moonlight Sonata|C# Major
Stop

Output
Sonata No.2 by Chopin in B Minor added to the collection!
Hungarian Rhapsody No.2 by Liszt in C# Minor added to the collection!
Fur Elise is already in the collection!
Successfully removed Clair de Lune!
Changed the key of Moonlight Sonata to C# Major!
Fur Elise -> Composer: Beethoven, Key: A Minor
Moonlight Sonata -> Composer: Beethoven, Key: C# Major
Sonata No.2 -> Composer: Chopin, Key: B Minor
Hungarian Rhapsody No.2 -> Composer: Liszt, Key: C# Minor

Explanaton
After we receive the initial pieces with their info,
we start receiving commands. The first two commands are to
add a piece to the collection, and since the pieces are not
already added, we manage to add them. The third add command,
however, attempts to add a piece, which is already in the collection,
so we print a special message and don't add the piece.
 After that, we receive the remove command, and since the piece
 is in the collection, we remove it successfully.
Finally, the last command says to change the key of a piece.
Since the key is present in the collection, we modify its key.
We receive the Stop command, print the information about the pieces, and the program ends.

____________________________________________________________________________________________
Example_02

Input
4
Eine kleine Nachtmusik|Mozart|G Major
La Campanella|Liszt|G# Minor
The Marriage of Figaro|Mozart|G Major
Hungarian Dance No.5|Brahms|G Minor
Add|Spring|Vivaldi|E Major
Remove|The Marriage of Figaro
Remove|Turkish March
ChangeKey|Spring|C Major
Add|Nocturne|Chopin|C# Minor
Stop

Output
Spring by Vivaldi in E Major added to the collection!
Successfully removed The Marriage of Figaro!
Invalid operation! Turkish March does not exist in the collection.
Changed the key of Spring to C Major!
Nocturne by Chopin in C# Minor added to the collection!
Eine kleine Nachtmusik -> Composer: Mozart, Key: G Major
La Campanella -> Composer: Liszt, Key: G# Minor
Hungarian Dance No.5 -> Composer: Brahms, Key: G Minor
Spring -> Composer: Vivaldi, Key: C Major
Nocturne -> Composer: Chopin, Key: C# Minor

"""

003 - Previous final Exams/01 Final Exam - Retake/03the_pianist.py


#!/usr/bin/env python

def check_path(fp):
    import os
    if not os.path.exists(fp):
        raise FileNotFoundError("Could not find the file {}".format(fp))

def main(sew_file, orb_file, hdf_file, symmetry, index):
    import re
    import numpy as np
    import h5py
    print(' ')
    print('           M U L L I K E N  A N A L Y S I S')
    print('                          of ')
    print('    Molecular Orbital in terms of Atomic Orbital wt.%')
    print(' ')
    print('For questions/suggestions contact Gaurab Ganguly')
    print('                                  gaurabganguly1989@gmail.com')
    print(' ')
    print('Molecular Orbital of interest:')
    print('------------------------------')
    print('Symmetry label=', symmetry,', Index=', index)
    print(' ')
    print('Files from Molcas/OpenMolcas Calculation:')
    print('-----------------------------------------')
    print('Seward file   :', sew_file)
    print('Orbital file  :', orb_file)
    print('HDF5 file     :', hdf_file)
    print(' ')
    print(' ')
    count = []          # index of basis fn (all irreps combined)
    basisfn = []        # total number of basis fn (all irreps combined)
    irrep = []          # irreps of the point group
    sym_label = []      # indexing the irreps 1,2,3,...
    sym_bas = []        # number of basis fn in each irrep
    sym_block = []      # elements of AO overlap matrix in each irrep block
    coeff = []          # store the MO coefficients of the requested MO in a list
    check_path(sew_file)
    check_path(orb_file)
    check_path(hdf_file)
    #Reading basis information from the provided SEWARD file:
    with open(sew_file, 'r') as sfile:
        for line in sfile:
            if re.search(r'Basis Label        Type   Center', line):
                for line in sfile:
                    if re.search(r'Basis set specifications \:', line):
                        break
                    if re.search(r'\W\d', line):
                        count.append(int(line.split()[0]))
                        basisfn.append(line.split()[1] + "-" + (line.split()[2]))
        if len(count) == 0 and len(basisfn) == 0:
            raise ValueError("Could not find basis set table in seward output file {}".format(sew_file))
    with open(sew_file, 'r') as sfile:
        lines = sfile.readlines()
        try:
            point_group = [x for x in lines if 'Character Table' in x][0].split()[3]
            symmetry_species = [x for x in lines if 'Symmetry species' in x][0]
            basis_functions = [x for x in lines if 'Basis functions' in x][-1]
            #print("BAS", basis_functions)
        except IndexError:
            raise IndexError("Could not find 'Character Table', 'Symmetry species', or 'Basis functions' " \
                             +"search strings in seward output file {}".format(sew_file))
        num_of_irreps = len(re.findall(r'\d+', basis_functions))
        if num_of_irreps == 0:
            raise ValueError("Did not find any Irreps. in seward output file {}".format(sew_file))
        for i in range(num_of_irreps):
            sym_label.append(i+1)
            irrep.append(symmetry_species.split()[i+2])
            sym_bas.append(int(basis_functions.split()[i+2]))
            sym_block.append(int(basis_functions.split()[i+2])**2)
    # Reading orbitals from GssOrb/ScfOrb/RASOrb/PT2Orb/SONOrb or any orbitals file:
    search_string = r'\* ORBITAL{:>5d}{:>5d}'
    with open(orb_file, 'r') as ofile:
        for line in ofile:
            if re.search(search_string.format(symmetry, index), line):
                for line in ofile:
                    if re.search(search_string.format(symmetry, index+1), line):
                        break
                    if re.search(r'\s', line):
                        for item in line.strip().split():
                            coeff.append(float(item))
        if len(coeff) == 0 and re.search(search_string.format(symmetry, index), line):
            # found the search string
            raise ValueError("Did not find orbitals in orbital file {}".format(orb_file))
        elif re.search(search_string.format(symmetry, index), line) is not None:
            # did not find the search string
            raise RuntimeError("Something else went wrong.......Help me PLS. :(")
    # Reading AO overlap integrals from the provided '.h5' file:
    with h5py.File(hdf_file, 'r') as hdf:
        overlap = np.array(hdf.get('AO_OVERLAP_MATRIX'))
    print('                 POINT GROUP =', point_group)
    print('-------------------------------------------------------------')
    print('Symm. label      Irrep.       No. of MOs')
    print('-------------------------------------------------------------')
    template = ' {:>10d}      {:<10s}  {:>10d}'
    for i in range(num_of_irreps):
        print(template.format(i+1, symmetry_species.split()[i+2], int(basis_functions.split()[i+2])))
    print('-------------------------------------------------------------')
    start_bas = 0
    start_block = 0
    end_bas = 0
    end_block = 0
    try:
        if symmetry == 1:
            end_bas = start_bas + sym_bas[0]
            end_block = start_block + sym_block[0]
            bas = np.array(basisfn[start_bas:end_bas])
            block = np.reshape(overlap[start_block:end_block], (sym_bas[0], sym_bas[0]))
        else:
            for i in range(symmetry-1):
                start_bas += sym_bas[i]
                start_block += sym_block[i]
            for i in range(symmetry):
                end_bas += sym_bas[i]
                end_block += sym_block[i]
            bas = np.array(basisfn[start_bas:end_bas])
            block = np.reshape(overlap[start_block:end_block], (sym_bas[symmetry-1],
                                                                sym_bas[symmetry-1]))
    # TODO: find out what exception it raises that you would have to deal with.
    #       having a general Exception is not good to do.
    #       python has the great ability to handle different error cases separately and you can give the
    #       user valuable information as to what went wrong when you raise the appropriate error.
    except Exception:
        print("Error Exit:")
        print("Symmetry label", symmetry, "is not possible for", point_group, "point group!")
        print("Check the table and re run.")
    # Multiplying coeff*overlap*coeff (CSC) to get MO wt%
    if symmetry == 0 or index == 0:
        # TODO: here a raise ValueError would be more appropriate also it will terminate the program
        print("Error Exit:")
        print("Symmetry or Index can't be 0!")
        print("Check the Symmetry label for Irreps in the table and re run.")
    elif symmetry not in sym_label:
        pass
    elif index > sym_bas[symmetry-1]:
        # TODO: here a raise ValueError would be more appropriate also it will terminate the program
        raise ValueError("Error Exit: Index", index, "is beyond range for", irrep[symmetry-1], \
                        "Irrep! Check the table and re run.")
        #print("Error Exit:")
        #print("Index", index, "is beyond range for", irrep[symmetry-1], "Irrep!")
        #print("Check the table and re run.")
    elif symmetry in sym_label and index <= sym_bas[symmetry-1]:
        print('')
        print('Mulliken Analysis of:')
        template = "n-th ('n ={:>3}') MO in '{}' Symmetry (symm. label = '{}')."
        print(template.format(index, irrep[symmetry - 1], symmetry))
        print('All AO function with > 1.0% weight in the MO is printed.')
        print('-------------------------------------------------------------')
        print('AO-func.          wt.%  ')
        print('-------------------------------------------------------------')
        for i in range(len(coeff)):
            tmp = []
            for j in range(len(coeff)):
                tmp.append(coeff[i] * block[i][j] * coeff[j])
            if abs(sum(tmp))*100 > 1.0 : # user can change the thresold
                print('{:<10s} {:>10.1f}%'.format(bas[i], sum(tmp)*100))
        print('-------------------------------------------------------------')
        print('')
    else:
        # TODO: here a raise ValueError would be more appropriate also it will terminate the program
        raise ValueError("Error Exit: Symmetry label and Index is not possible! Check and re run.")
        #print("Error Exit: Symmetry label and Index is not possible! Check and re run.")

if __name__ == "__main__":
    import argparse, pathlib
    parser = argparse.ArgumentParser(description="This program calculates AO wt% in a given MO.")
    parser.add_argument('sew_file', type=pathlib.Path, metavar='1) file.out',
                        help="Gateway/Seward output file with print level = 3.")
    parser.add_argument('orb_file', type=pathlib.Path, metavar='2) file.SCF/RAS/SONOrb',
                        help="Orbital file with MO co-efficients.")
    parser.add_argument('hdf_file', type=pathlib.Path, metavar='3) file.h5',
                        help="HDF5 file for AO overlap matrix.")
    parser.add_argument('-s',  '--symmetry', type=int, metavar='MO_symmetry', required=True,
                        help="Symmetry/Irrep of the orbital of interest.")
    parser.add_argument('-i',  '--index',    type=int, metavar='MO_Index', required=True,
                        help="Orbital index in the particular Symmetry/Irrep.")
    args = parser.parse_args()
    main(args.sew_file, args.orb_file, args.hdf_file, args.symmetry, args.index)


#baekjoon_1072_게임

#=== import module ===#

#=== variable declare ===#

#=== Function define ===#

#=== main function ===#
x,y = map(int,input().split()); #게임 횟수, 이긴 횟수
currentRate = y*100 // x;
if currentRate >= 99: print(-1); exit(0);

high = 1000000000;
row = 0;
result = -1;
while(row <= high):

  mid = (high + row) // 2;
  rate = (y + mid) * 100 // (x + mid);

  if currentRate >= rate:
    row = mid + 1;
    result = mid + 1;
  else:
    high = mid - 1;

print(result);


from decimal import Decimal
from background.celery_app import app as celery_app
from services.csmoney import DotaDataProcessor
from settings.config import SERVICES, CSMONEY
from models.dota.item import DotaItem
from models.dota.hero import Hero
from models.dota.service_price import ServicePrice
from models.dota.specification import Rarity, Quality, ItemType, Slot
from extentions import db

@celery_app.task(name="update_service_price", queue="items_base_queue")
def update_service_price(
        game_id: int,
        item_hash_name: str,
        price: Decimal,
        service: str,
        hero_name: str = None,
        rarity: str = None,
        item_type: str = None,
        slot: str = None,
        quality: str = None
):
    if service not in SERVICES:
        raise f"No such service {service}"
    if game_id == 570:
        item = DotaItem.query.filter_by(name=item_hash_name).one_or_none()
        if not item and service == CSMONEY:
            item = DotaItem(
                name=item_hash_name,
                quality=Quality(quality).name,
                rarity=Rarity(rarity).name,
                item_type=ItemType(item_type).name,
                slot=Slot(slot).name
            )
            hero = Hero.query.filter_by(name=hero_name).one_or_none()
            if not hero and hero_name:
                hero = Hero(
                    name=hero_name
                )
                hero.items.append(item)
                db.session.add(hero)
            else:
                if hero:
                    item.hero_id = hero.id
            db.session.add(item)

        if not item:
            return {
                "error": "Cant update with not cs money"
            }

        service_price = ServicePrice.query.filter_by(service=service, item=item).one_or_none()
        if not service_price:
            service_price = ServicePrice(
                service=service,
                price=price
            )
            item.prices.append(service_price)
        else:
            service_price.price = price
        if service_price:
            db.session.add(service_price)
        db.session.commit()
    elif game_id == 730:
        pass
    else:
        raise Exception("No such a game")