var PARAMETERS = {
    "timedMemories": 0, 
    "focusPanelKey": "focusPanel", 
    "dayTicks": 150, 
    "currencyBoost": "currencyBoost", 
    "startEntities": [
        "difficultySetting", 
        "gameStateEntity", 
        "self", 
        "himself", 
        "day", 
        "controlPanel", 
        "chapter1", 
        "autosaver", 
        "trainPathMakingPanel", 
        "utilityPanel", 
        "dayPanel", 
        "focusPanel", 
        "buildPanel", 
        "cursor", 
        "currencyRenderEntity", 
        "pointCounter"
    ], 
    "damageIndicator": "damageIndicator", 
    "trainPathMakingPanel": "trainPathMakingPanel", 
    "lostControl": "lostControl", 
    "baseButtonName": "baseButton", 
    "buildingConnect": 1, 
    "path": "path", 
    "trainPath": "trainPath", 
    "creepHit": [
        "lostControl", 
        "selfDamageEffect", 
        "disableMemories"
    ], 
    "interactionKeys": [
        "self", 
        "himself"
    ], 
    "currencyRenderEntity": "currencyRenderEntity", 
    "size": [
        13, 
        23
    ], 
    "buildPanel": "buildPanel", 
    "settingsPanel": "settingsPanel", 
    "chapterPanel": "chapterPanel", 
    "selfExtension": "selfExtension", 
    "qualityMine": "qualityMine", 
    "memoryConstruction": "memoryConstruction", 
    "wishesToBeMaking": 0, 
    "buildablePaths": 0, 
    "memoryStopGoal": "memoryStopGoal", 
    "ensureExistence": [
        "difficultySetting"
    ], 
    "randomMenuMarker": "randomMenuMarker", 
    "memory": "memory", 
    "carriage": "carriage", 
    "ticksPerTick": [
        2, 
        5
    ], 
    "towerPanel": "entityPanel", 
    "selfDeadMenu": "breakdownMenu", 
    "utilityPanel": "utilityPanel", 
    "difficultySetting": "difficultySetting", 
    "junction": "junction", 
    "extensionMonitorEnabled": 0, 
    "trainPanel": "trainPanel", 
    "trainPathMaker": "trainPathMaker", 
    "newParticle": "newParticle", 
    "openMenu": "openMenu", 
    "gameStageStartMenu": "gameStageStartMenu", 
    "towerFlash": "towerFlash", 
    "train": "train", 
    "emotionSource": "emotionSource", 
    "goalComplete": "goalComplete", 
    "allTrainPanel": "allTrainPanel", 
    "maxExperience": 8, 
    "startEntityGroups": [
        "emotionState", 
        "emotionCurrencyTicker", 
        "emotionEntityMaker", 
        "notificationCurrency", 
        "emotionResourceMap", 
        "setPanel", 
        "selfExtension", 
        "currencyOverload", 
        "checkQuality", 
        "currencyOverload", 
        "currencyAction", 
        "personCurrencyAction"
    ], 
    "day": "day", 
    "gameStateEntity": "gameStateEntity", 
    "addPoints": "addPoints", 
    "bullet": "bullet", 
    "sectors": [
        5, 
        8
    ], 
    "currencyRequest": "currencyRequest", 
    "clickText": "clickText", 
    "resourceModifiers": 0, 
    "traitPanel": "traitPanel", 
    "toast": "toast", 
    "pointNotification": "pointNotification", 
    "carryTrain": "carryTrain", 
    "allGoalPanel": "allGoalPanel", 
    "construction": "construction", 
    "allBuildingPanel": "allBuildingPanel", 
    "notification": "notification", 
    "autosaveKey": "autosave_flip", 
    "singleUseTrainPath": "singleUseTrainPath", 
    "defaultHeldOpinions": [
        "acquaintance"
    ], 
    "self": "self", 
    "creepSelfDamage": 10
};

var allArgs = {
    "callousnessAction": {
        "currenciesRequired": [
            "selfishness"
        ], 
        "towerKey": "callousnessTower", 
        "name": "Callousness", 
        "key": "callousnessAction"
    }, 
    "makeWorkWinMajorButton": {
        "constructionKey": "makeWorkWinMajorGoalConstruction", 
        "name": "Talk About Work Success", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeWorkWinMajorGoal", 
        "key": "makeWorkWinMajorButton", 
        "description": "Requires major, dream completion."
    }, 
    "memory_joyBurst": {
        "image": "trait-e6e617", 
        "memoryEmotions": [
            "joy"
        ], 
        "key": "memory_joyBurst", 
        "name": "Joy"
    }, 
    "getFeedbackGoal": {
        "key": "getFeedbackGoal", 
        "randomPosition": 0, 
        "name": "Get Feedback", 
        "image": "goal_hook-000000", 
        "currencyRequested": {
            "will": 3, 
            "workTopic": 3
        }, 
        "entitiesToMake": "criticismFlat", 
        "goalMenuKey": "getFeedbackMenu"
    }, 
    "obsessButton": {
        "constructionKey": "obsessGoalConstruction", 
        "name": "Obsess", 
        "image": "goal_motivation-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "obsessGoal", 
        "key": "obsessButton", 
        "description": [
            "Requires envy, insecurity.", 
            "Makes obsession."
        ]
    }, 
    "youInfo": {
        "name": "Info on You", 
        "key": "youInfo", 
        "tags": [
            "youInfo"
        ]
    }, 
    "winButton": {
        "constructionKey": "winGoalConstruction", 
        "name": "Win Game!", 
        "image": "goal_trophy-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "winGoal", 
        "key": "winButton", 
        "description": "Requires his emotion."
    }, 
    "casualSwarmYouMineConstruction": {
        "key": "casualSwarmYouMineConstruction", 
        "constructionIdentifier": "casualSwarmYouMine", 
        "name": "Casual Cruelty", 
        "image": "tower_mineCaution-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Casual Cruelty"
    }, 
    "himSupportGoal": {
        "key": "himSupportGoal", 
        "randomPosition": 1, 
        "name": "Get Support", 
        "makeOnTimeOut": "noSupportGoal", 
        "image": "goal_heart-000000", 
        "currencyRequested": {
            "support": 3
        }, 
        "goalMenuKey": "himSupportMenu", 
        "timeToDeath": 150
    }, 
    "friendMeditateTower": {
        "image": "tower_goalCalmDown-000000", 
        "activeImage": "tower_goalCalmDown-000000_activeOutline-0099ff", 
        "name": "Be Calmed Down", 
        "key": "friendMeditateTower", 
        "description": "Converts social -> calm"
    }, 
    "calmnessMineConstruction": {
        "key": "calmnessMineConstruction", 
        "constructionIdentifier": "calmnessMine", 
        "name": "Constructing - Calmness", 
        "image": "trait-aaaaaa99_tower_wave", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Calmness", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "hisWork_ext": {
        "personHeld": "him", 
        "image": [
            "trait-ff66ff", 
            "trait-E55BE5", 
            "trait-FF70FF"
        ], 
        "name": "His Work", 
        "key": "hisWork_ext", 
        "sourceKey": "hisWork"
    }, 
    "takeSupportAction": {
        "currenciesRequired": [
            "support"
        ], 
        "towerKey": "takeSupportTower", 
        "name": "Supported!", 
        "key": "takeSupportAction"
    }, 
    "restlessPathNewRelationship": {
        "startKey": "restless", 
        "endKey": "newRelationship", 
        "key": "restlessPathNewRelationship"
    }, 
    "tryNewResult": {
        "goodEntities": "exploreNewGoal", 
        "badEntities": {
            "resentYou": 4
        }, 
        "key": "tryNewResult"
    }, 
    "trySomethingGoalConstruction": {
        "key": "trySomethingGoalConstruction", 
        "constructionIdentifier": "trySomethingGoal", 
        "name": "Constructing - Try Something New", 
        "image": "trait-aaaaaa99_goal_trophy-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Try Something New", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "viceTowerConstruction": {
        "key": "viceTowerConstruction", 
        "constructionIdentifier": "viceTower", 
        "name": "Constructing - Indulge Vice", 
        "image": "trait-aaaaaa99_tower_newNote", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Indulge Vice", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "resentYouMine": {
        "resourceCount": 1, 
        "name": "Resent Your Failures", 
        "image": "tower_discard", 
        "key": "resentYouMine", 
        "emotionTags": [
            "anger", 
            "self", 
            "resentMed"
        ], 
        "resourceKeys": [
            "resentMed"
        ], 
        "activeImage": "tower_discard_activeOutline-0099ff", 
        "description": "makes resentMed"
    }, 
    "slowWorkSwarm": {
        "resourceCount": 3, 
        "name": "Slow Work", 
        "image": "tower_memoryDefineSelf", 
        "destination": "himself", 
        "key": "slowWorkSwarm", 
        "emotionTags": [
            "anger"
        ], 
        "resourceKeys": "slowWorkSmall", 
        "activeImage": "tower_memoryDefineSelf_activeOutline-0099ff"
    }, 
    "exploreNewResult": {
        "goodEntities": "exploreNewGoal", 
        "badEntities": [
            "resentYou", 
            "resentYou", 
            "interestingDeposit"
        ], 
        "key": "exploreNewResult"
    }, 
    "insecurityToSearchingWorth": {
        "sourceTrait": "insecurity", 
        "newTrait": "searchingWorth", 
        "key": "insecurityToSearchingWorth"
    }, 
    "himSupportButton": {
        "constructionKey": "himSupportTowerConstruction", 
        "name": "Support", 
        "image": "tower_dependence", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "himSupportTower", 
        "limitingKeys": [
            "himSupportTower", 
            "himSupportTowerConstruction"
        ], 
        "key": "himSupportButton", 
        "subPanel": "Towers", 
        "description": "Converts strength -> support"
    }, 
    "distractTower": {
        "image": "tower_mineCheer", 
        "activeImage": "tower_mineCheer_activeOutline-0099ff", 
        "name": "Distract", 
        "key": "distractTower", 
        "description": "Converts social + need -> distraction"
    }, 
    "talkHappy": {
        "resourceCount": 3, 
        "name": "Happiness From Talking", 
        "image": "tower_goalConvinceWife-000000", 
        "destination": "himself", 
        "key": "talkHappy", 
        "emotionTags": [
            "joy"
        ], 
        "resourceKeys": "complimentSmall", 
        "activeImage": "tower_goalConvinceWife-000000_activeOutline-0099ff"
    }, 
    "fascinateGoalConstruction": {
        "key": "fascinateGoalConstruction", 
        "constructionIdentifier": "fascinateGoal", 
        "name": "Constructing - Fascinate The Clever Friend", 
        "image": "trait-aaaaaa99_goal_spark-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Fascinate The Clever Friend", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "spendTimeGoalConstruction": {
        "key": "spendTimeGoalConstruction", 
        "constructionIdentifier": "spendTimeGoal", 
        "name": "Constructing - Spend Some Time", 
        "image": "trait-aaaaaa99_goal_goalBuyTime-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Spend Some Time", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "guiltFlatYouMineConstruction": {
        "key": "guiltFlatYouMineConstruction", 
        "constructionIdentifier": "guiltFlatYouMine", 
        "name": "Guilt", 
        "image": "tower_eyeTear-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Guilt"
    }, 
    "openResponseMenu": {
        "image": "goal_towerFlirt-000000", 
        "name": "COMPLETED - Open Response", 
        "key": "openResponseMenu"
    }, 
    "askHelpButton": {
        "constructionKey": "askHelpGoalConstruction", 
        "name": "Ask For Help", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "askHelpGoal", 
        "key": "askHelpButton", 
        "description": "Requires social."
    }, 
    "relationshipPathHisWork": {
        "startKey": "relationship", 
        "endKey": "hisWork", 
        "key": "relationshipPathHisWork"
    }, 
    "cleverPathRestless": {
        "startKey": "clever", 
        "endKey": "restless", 
        "key": "cleverPathRestless"
    }, 
    "acceptMeanlessMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Accept Meaninglessness", 
        "key": "acceptMeanlessMenu"
    }, 
    "planSomethingFunMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Plan Something Fun", 
        "key": "planSomethingFunMenu"
    }, 
    "makeCriticismSwarmGoal": {
        "key": "makeCriticismSwarmGoal", 
        "randomPosition": 0, 
        "name": "Make Swarm of Criticisms", 
        "image": "goal_mineFrustration-000000", 
        "currencyRequested": {
            "criticism": 3, 
            "swarm": 3
        }, 
        "entitiesToMake": "criticismSwarm", 
        "goalMenuKey": "makeCriticismSwarmMenu"
    }, 
    "doFunMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Do Something Fun!", 
        "key": "doFunMenu"
    }, 
    "openUpGoalConstruction": {
        "key": "openUpGoalConstruction", 
        "constructionIdentifier": "openUpGoal", 
        "name": "Constructing - Open Up", 
        "image": "trait-aaaaaa99_goal_goalConvinceWife-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Open Up", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "jealousyBurst": {
        "emotionsToAdd": {
            "anger": 1
        }, 
        "name": "Jealousy", 
        "image": "tower_depositSin", 
        "key": "jealousyBurst", 
        "memoryKey": "memory_jealousyBurst", 
        "emotionTags": "self", 
        "resourceKey": "jealousyBurstMineConstruction", 
        "activeImage": "tower_depositSin_activeOutline-0099ff"
    }, 
    "partnerInfoDeposit": {
        "image": "tower_book", 
        "activeImage": "tower_book_activeOutline-0099ff", 
        "name": "Info on Partner", 
        "key": "partnerInfoDeposit", 
        "deposit": {
            "partnerInfo": 3
        }
    }, 
    "crueltyButton": {
        "constructionKey": "crueltyTowerConstruction", 
        "name": "Cruelty", 
        "image": "tower_goalDisavowal-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "crueltyTower", 
        "limitingKeys": [
            "crueltyTower", 
            "crueltyTowerConstruction"
        ], 
        "key": "crueltyButton", 
        "subPanel": "Towers", 
        "description": "Converts frustration -> cruelty"
    }, 
    "viceFlatYouMine": {
        "resourceCount": 1, 
        "name": "Vice", 
        "image": "tower_memoryRing", 
        "key": "viceFlatYouMine", 
        "emotionTags": [
            "joy", 
            "self", 
            "viceMed"
        ], 
        "resourceKeys": [
            "viceMed"
        ], 
        "activeImage": "tower_memoryRing_activeOutline-0099ff", 
        "description": "makes viceMed"
    }, 
    "soberDownMenu": {
        "image": "goal_goalCalmDown-000000", 
        "name": "COMPLETED - Sober Down", 
        "key": "soberDownMenu"
    }, 
    "startConverseGoal": {
        "key": "startConverseGoal", 
        "randomPosition": 0, 
        "name": "Start Conversation", 
        "image": "goal_goalConvinceWife-000000", 
        "currencyRequested": {
            "social": 3
        }, 
        "entitiesToMake": "conversation", 
        "goalMenuKey": "startConverseMenu"
    }, 
    "talkAboutYouGoalConstruction": {
        "key": "talkAboutYouGoalConstruction", 
        "constructionIdentifier": "talkAboutYouGoal", 
        "name": "Constructing - Talk About You", 
        "image": "trait-aaaaaa99_goal_newNote-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Talk About You", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "funPathHurting": {
        "startKey": "fun", 
        "endKey": "hurting", 
        "key": "funPathHurting"
    }, 
    "searchingWorth": {
        "name": "Searching For Worth", 
        "image": "trait-00aa00", 
        "personHeld": "you", 
        "isaacEntities": [
            "acceptMeanlessButton", 
            "rejectMeanlessButton", 
            "defineHelpButton", 
            "tryNewButton"
        ], 
        "key": "searchingWorth", 
        "interactionKeys": [
            "self"
        ]
    }, 
    "complimentYouButton": {
        "constructionKey": "complimentYouGoalConstruction", 
        "name": "Compliment You", 
        "image": "goal_mineCheer-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "complimentYouGoal", 
        "key": "complimentYouButton", 
        "description": "Requires cheer."
    }, 
    "getOverGoodWorkButton": {
        "constructionKey": "getOverGoodWorkGoalConstruction", 
        "name": "Get Over Good Work", 
        "image": "goal_weight-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "getOverGoodWorkGoal", 
        "key": "getOverGoodWorkButton", 
        "description": "Requires will."
    }, 
    "goalHelpInfoPanel": {
        "components": [
            "worldGoalComponent"
        ], 
        "helpLines": [
            "These are things that your character wants.", 
            "They are completed by connecting it to the rest of the mind and generating the currencies that it requests."
        ], 
        "name": "Goals", 
        "key": "goalHelpInfoPanel"
    }, 
    "oldFailMine": {
        "image": "tower_mineSocial", 
        "resourceKeys": [
            "pain"
        ], 
        "name": "Old Failings", 
        "key": "oldFailMine", 
        "activeImage": "tower_mineSocial_activeOutline-0099ff"
    }, 
    "flirtationMine": {
        "image": "tower_towerFlirt", 
        "resourceKeys": [
            "flirtation"
        ], 
        "name": "Flirtation", 
        "key": "flirtationMine", 
        "activeImage": "tower_towerFlirt_activeOutline-0099ff"
    }, 
    "complimentSwarmYouMineConstruction": {
        "key": "complimentSwarmYouMineConstruction", 
        "constructionIdentifier": "complimentSwarmYouMine", 
        "name": "Compliment", 
        "image": "tower_memoryRing-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Compliment"
    }, 
    "noticeThingGoal": {
        "key": "noticeThingGoal", 
        "randomPosition": 1, 
        "name": "Notice Something About Him", 
        "image": "goal_book-000000", 
        "currencyRequested": {
            "openness": 1
        }, 
        "entitiesToMake": "partnerInfoDeposit", 
        "goalMenuKey": "noticeThingMenu", 
        "timeToDeath": 60
    }, 
    "startConverseMenu": {
        "image": "goal_goalConvinceWife-000000", 
        "name": "COMPLETED - Start Conversation", 
        "key": "startConverseMenu"
    }, 
    "tryNewGoalConstruction": {
        "key": "tryNewGoalConstruction", 
        "constructionIdentifier": "tryNewGoal", 
        "name": "Constructing - Try Something New", 
        "image": "trait-aaaaaa99_goal_spark-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Try Something New", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "stateAction": {
        "currenciesRequired": [
            "social"
        ], 
        "towerKey": "stateTower", 
        "currenciesToMake": [
            "state"
        ], 
        "name": "Make Statement", 
        "key": "stateAction"
    }, 
    "viceFlatHim": {
        "resourceCount": 1, 
        "name": "Vice", 
        "image": "tower_memoryRing", 
        "destination": "himself", 
        "key": "viceFlatHim", 
        "emotionTags": [
            "joy"
        ], 
        "resourceKeys": "viceMed", 
        "activeImage": "tower_memoryRing_activeOutline-0099ff"
    }, 
    "fearTickModifier": {
        "timeToDeath": 15
    }, 
    "minorInterruptMenu": {
        "image": "goal_mineFrustration-000000", 
        "name": "COMPLETED - Interrupt Partner", 
        "key": "minorInterruptMenu"
    }, 
    "anxietyMineButton": {
        "constructionKey": "anxietyMineConstruction", 
        "name": "Anxiety", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_mineCaution", 
        "currenciesMade": [
            "anxiety"
        ], 
        "entityKey": "anxietyMine", 
        "limitingKeys": [
            "anxietyMine", 
            "anxietyMineConstruction"
        ], 
        "key": "anxietyMineButton", 
        "description": "makes anxiety"
    }, 
    "hisBadWorkToHisWork": {
        "sourceTrait": "hisBadWork", 
        "newTrait": "hisWork", 
        "key": "hisBadWorkToHisWork"
    }, 
    "personGoal": {
        "minSelfDist": 4
    }, 
    "flashback_viceMedConstruction": {
        "key": "flashback_viceMedConstruction", 
        "constructionIdentifier": "flashback_viceMed", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "forceOpennessMenu": {
        "image": "goal_weight-000000", 
        "completeText": "This is easier for most people. It's certainly easier for him.", 
        "name": "COMPLETED - Force Some Openness", 
        "key": "forceOpennessMenu"
    }, 
    "hisGoodWorkToRestless": {
        "sourceTrait": "hisGoodWork", 
        "newTrait": "restless", 
        "key": "hisGoodWorkToRestless"
    }, 
    "obsessHimAction": {
        "currenciesRequired": [
            "partnerInfo"
        ], 
        "towerKey": "obsessHimTower", 
        "currenciesToMake": [
            "obsession"
        ], 
        "name": "Obsess About Him", 
        "key": "obsessHimAction"
    }, 
    "makeCriticismSwarmGoalConstruction": {
        "key": "makeCriticismSwarmGoalConstruction", 
        "constructionIdentifier": "makeCriticismSwarmGoal", 
        "name": "Constructing - Make Swarm of Criticisms", 
        "image": "trait-aaaaaa99_goal_mineFrustration-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Make Swarm of Criticisms", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "himSupportMenu": {
        "image": "goal_heart-000000", 
        "name": "COMPLETED - Get Support", 
        "key": "himSupportMenu"
    }, 
    "obsessGoalConstruction": {
        "key": "obsessGoalConstruction", 
        "constructionIdentifier": "obsessGoal", 
        "name": "Constructing - Obsess", 
        "image": "trait-aaaaaa99_goal_motivation-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Obsess", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "takeOutFrustrationGoal": {
        "key": "takeOutFrustrationGoal", 
        "randomPosition": 0, 
        "name": "Take Out Frustrations", 
        "image": "goal_mineFrustration-000000", 
        "currencyRequested": {
            "frustration": 3
        }, 
        "entitiesToMake": "criticismSwarmYou", 
        "goalMenuKey": "takeOutFrustrationMenu"
    }, 
    "resentYouMineConstruction": {
        "key": "resentYouMineConstruction", 
        "constructionIdentifier": "resentYouMine", 
        "name": "Resent Your Failures", 
        "image": "tower_discard-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Resent Your Failures"
    }, 
    "restlessToHisWork": {
        "sourceTrait": "restless", 
        "newTrait": "hisWork", 
        "key": "restlessToHisWork"
    }, 
    "meditation": {
        "name": "meditation", 
        "key": "meditation", 
        "tags": [
            "meditation"
        ]
    }, 
    "flashback_oldFailMed": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_oldFailMed", 
        "emotionTags": "oldFailMed", 
        "resourceKeys": [
            "oldFailMed"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes oldFailMed"
    }, 
    "criticismSmall": {
        "emotion": "sadness", 
        "name": "criticism", 
        "image": "creep-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 20, 
        "key": "criticismSmall"
    }, 
    "cleverPathRelationship": {
        "startKey": "clever", 
        "endKey": "relationship", 
        "key": "cleverPathRelationship"
    }, 
    "hisBadWorkToRestless": {
        "sourceTrait": "hisBadWork", 
        "newTrait": "restless", 
        "key": "hisBadWorkToRestless"
    }, 
    "noticeThingMenu": {
        "image": "goal_book-000000", 
        "name": "COMPLETED - Notice Something About Him", 
        "key": "noticeThingMenu"
    }, 
    "reachOutButton": {
        "constructionKey": "reachOutGoalConstruction", 
        "name": "Reach Out To Someone", 
        "image": "goal_goalMeetNewPerson-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "reachOutGoal", 
        "key": "reachOutButton", 
        "description": "Requires will."
    }, 
    "tiredSmall": {
        "emotion": "sadness", 
        "name": "fatigue", 
        "image": "creep-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 20, 
        "key": "tiredSmall"
    }, 
    "spendTimeGoal": {
        "key": "spendTimeGoal", 
        "randomPosition": 0, 
        "name": "Spend Some Time", 
        "image": "goal_goalBuyTime-000000", 
        "currencyRequested": {
            "relationshipTime": 3
        }, 
        "entitiesToMake": "spendTimeResult", 
        "goalMenuKey": "spendTimeMenu"
    }, 
    "truthButton": {
        "constructionKey": "truthTowerConstruction", 
        "name": "Speak Truth", 
        "image": "tower_newNote", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "truthTower", 
        "limitingKeys": [
            "truthTower", 
            "truthTowerConstruction"
        ], 
        "key": "truthButton", 
        "subPanel": "Towers", 
        "description": "Converts insecurity -> truth"
    }, 
    "niceGoal": {
        "key": "niceGoal", 
        "randomPosition": 1, 
        "name": "Be Nice To You", 
        "image": "goal_towerFlirt-000000", 
        "currencyRequested": {
            "social": 3
        }, 
        "entitiesToMake": "complimentSwarmYou", 
        "interactionKeys": [
            "himself"
        ], 
        "goalMenuKey": "niceMenu", 
        "description": "He is really nice when he remembers to be."
    }, 
    "openUpGoal": {
        "key": "openUpGoal", 
        "randomPosition": 0, 
        "name": "Open Up", 
        "image": "goal_goalConvinceWife-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": [
            "takeSupportTowerPlaced", 
            "takeSupportTowerPlaced", 
            "openUpDone"
        ], 
        "goalMenuKey": "openUpMenu"
    }, 
    "selfEsteem": {
        "name": "self-esteem", 
        "key": "selfEsteem", 
        "tags": [
            "selfEsteem"
        ]
    }, 
    "insecurity_ext": {
        "personHeld": "you", 
        "image": [
            "trait-339900", 
            "trait-2D8900", 
            "trait-38A800"
        ], 
        "name": "Insecurity", 
        "key": "insecurity_ext", 
        "sourceKey": "insecurity"
    }, 
    "calmnessTower": {
        "description": "Uses calm to calm anger, joy, sadness", 
        "charges": 5, 
        "image": "tower_wave", 
        "damage": 20, 
        "damageMultipliers": {
            "anger": 1, 
            "joy": 1, 
            "sadness": 1
        }, 
        "impulseTicks": 1, 
        "key": "calmnessTower", 
        "activeImage": "tower_wave_activeOutline-0099ff", 
        "name": "Calmness"
    }, 
    "acceptConnectionHimGoal": {
        "key": "acceptConnectionHimGoal", 
        "randomPosition": 0, 
        "name": "Accept Connection", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "youInfo": 3
        }, 
        "entitiesToMake": [
            "clearNewRelationship", 
            "newRelationshipToRelationship"
        ], 
        "interactionKeys": [
            "himself"
        ], 
        "goalMenuKey": "acceptConnectionHimMenu", 
        "timeToDeath": 300
    }, 
    "newRelationship_ext": {
        "personHeld": "relation", 
        "image": [
            "trait-ff0000", 
            "trait-E50000", 
            "trait-FF0000"
        ], 
        "name": "New Relationship", 
        "key": "newRelationship_ext", 
        "sourceKey": "newRelationship"
    }, 
    "needHelpMenu": {
        "image": "goal_minePain-000000", 
        "completeText": [
            "It's okay to need help sometimes. He's willing to switch places for a", 
            "while."
        ], 
        "name": "COMPLETED - Need Help Yourself", 
        "key": "needHelpMenu"
    }, 
    "overcomeCrisisButton": {
        "constructionKey": "overcomeCrisisGoalConstruction", 
        "name": "Overcome Crisis", 
        "image": "goal_motivation-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "overcomeCrisisGoal", 
        "key": "overcomeCrisisButton", 
        "interactionKeys": [
            "himself"
        ], 
        "description": "Requires resolve."
    }, 
    "socialAction": {
        "towerKey": "socialTower", 
        "name": "Social", 
        "entitiesOnConvert": {
            "noticeThingGoal": 25
        }, 
        "currenciesRequired": [
            "openness"
        ], 
        "currenciesToMake": [
            "social"
        ], 
        "key": "socialAction"
    }, 
    "startRelationHimGoalConstruction": {
        "key": "startRelationHimGoalConstruction", 
        "constructionIdentifier": "startRelationHimGoal", 
        "name": "Constructing - Start Relationship", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Start Relationship", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "tryForConnectionHimGoalConstruction": {
        "key": "tryForConnectionHimGoalConstruction", 
        "constructionIdentifier": "tryForConnectionHimGoal", 
        "name": "Constructing - Try For Connection", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Try For Connection", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "caringTower": {
        "image": "tower_minePain", 
        "activeImage": "tower_minePain_activeOutline-0099ff", 
        "name": "Caring", 
        "key": "caringTower", 
        "description": "Converts goodness -> caring"
    }, 
    "quietTimeMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Quiet Time Together", 
        "key": "quietTimeMenu"
    }, 
    "shareJoyTower": {
        "description": "Uses social to calm joy", 
        "charges": 5, 
        "image": "tower_mineCheer", 
        "damage": 20, 
        "damageMultipliers": {
            "joy": 1
        }, 
        "impulseTicks": 1, 
        "key": "shareJoyTower", 
        "activeImage": "tower_mineCheer_activeOutline-0099ff", 
        "name": "Sharing Joy"
    }, 
    "obsessHimTower": {
        "image": "tower_hook", 
        "activeImage": "tower_hook_activeOutline-0099ff", 
        "name": "Obsess About Him", 
        "key": "obsessHimTower", 
        "description": "Converts Info on Partner -> obsession"
    }, 
    "makeOldFailFlatGoalConstruction": {
        "key": "makeOldFailFlatGoalConstruction", 
        "constructionIdentifier": "makeOldFailFlatGoal", 
        "name": "Constructing - Make Statement of Old Failures", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Make Statement of Old Failures", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "hisWorkToHisGoodWork": {
        "sourceTrait": "hisWork", 
        "newTrait": "hisGoodWork", 
        "key": "hisWorkToHisGoodWork"
    }, 
    "path": {
        "planeOfExistence": "path"
    }, 
    "strong": {
        "sector": [
            1, 
            6
        ], 
        "name": "Strong", 
        "image": "trait-33ff33", 
        "personHeld": "hurt", 
        "isaacEntities": [
            "strengthMineButton", 
            "himSupportButton"
        ], 
        "key": "strong", 
        "interactionKeys": [
            "himself"
        ], 
        "maxLevel": 6
    }, 
    "findHelpButton": {
        "constructionKey": "findHelpGoalConstruction", 
        "name": "Find Way To Be Helpful", 
        "image": "goal_heart-000000", 
        "description": "Requires Info on Partner.", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "findHelpGoal", 
        "key": "findHelpButton", 
        "displayRiskIcon": 1
    }, 
    "needBusyTowerConstruction": {
        "key": "needBusyTowerConstruction", 
        "constructionIdentifier": "needBusyTower", 
        "name": "Constructing - Need Help", 
        "image": "trait-aaaaaa99_tower_droop", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Need Help", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "startRelationYouButton": {
        "constructionKey": "startRelationYouGoalConstruction", 
        "name": "Start Relationship", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "startRelationYouGoal", 
        "key": "startRelationYouButton", 
        "description": [
            "Requires openness.", 
            "Makes value."
        ]
    }, 
    "openUpDone": {
        "buttonKey": "openUpButton", 
        "flag": "openUpDone", 
        "key": "openUpDone"
    }, 
    "giveInGoalConstruction": {
        "key": "giveInGoalConstruction", 
        "constructionIdentifier": "giveInGoal", 
        "name": "Constructing - Give In To Hurt", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Give In To Hurt", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "makeComplimentFlatGoal": {
        "key": "makeComplimentFlatGoal", 
        "randomPosition": 0, 
        "name": "Make Complimentary Statement", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "compliment": 3, 
            "social": 3
        }, 
        "entitiesToMake": "complimentFlat", 
        "goalMenuKey": "makeComplimentFlatMenu"
    }, 
    "memory_jealousyBurst": {
        "image": "trait-aa1717", 
        "memoryEmotions": [
            "anger"
        ], 
        "key": "memory_jealousyBurst", 
        "name": "Jealousy"
    }, 
    "oldFailMineConstruction": {
        "key": "oldFailMineConstruction", 
        "constructionIdentifier": "oldFailMine", 
        "name": "Constructing - Old Failings", 
        "image": "trait-aaaaaa99_tower_mineSocial", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Old Failings", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "largeValueDeposit": {
        "randomPosition": 1, 
        "name": "Value", 
        "image": "tower_trophy", 
        "deposit": {
            "value": 20
        }, 
        "key": "largeValueDeposit", 
        "interactionKeys": [
            "self"
        ], 
        "activeImage": "tower_trophy_activeOutline-0099ff"
    }, 
    "complimentButton": {
        "constructionKey": "complimentTowerConstruction", 
        "name": "Compliment", 
        "image": "tower_newNote", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "complimentTower", 
        "limitingKeys": [
            "complimentTower", 
            "complimentTowerConstruction"
        ], 
        "key": "complimentButton", 
        "subPanel": "Towers", 
        "description": "Converts completeWork + generosity -> compliment"
    }, 
    "meditativeMineButton": {
        "constructionKey": "meditativeMineConstruction", 
        "name": "Meditation", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_goalCalmDown-000000", 
        "currenciesMade": [
            "meditation"
        ], 
        "entityKey": "meditativeMine", 
        "limitingKeys": [
            "meditativeMine", 
            "meditativeMineConstruction"
        ], 
        "key": "meditativeMineButton", 
        "description": "makes meditation"
    }, 
    "oldFailFlat": {
        "resourceCount": 1, 
        "name": "Old Failures", 
        "image": "tower_eyeTear", 
        "destination": "himself", 
        "key": "oldFailFlat", 
        "emotionTags": [
            "sadness"
        ], 
        "resourceKeys": "oldFailMed", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "beSupportedBranch": {
        "flagToCheck": "beSupportedDone", 
        "key": "beSupportedBranch", 
        "notFlagEntities": "beSupportedButton"
    }, 
    "callousnessTowerPlaced": {
        "y": 23, 
        "x": 13, 
        "tower": "callousnessTower", 
        "key": "callousnessTowerPlaced"
    }, 
    "strengthMine": {
        "image": "tower_weight", 
        "resourceKeys": [
            "strength"
        ], 
        "name": "Strength", 
        "key": "strengthMine", 
        "activeImage": "tower_weight_activeOutline-0099ff"
    }, 
    "thinkMineButton": {
        "constructionKey": "thinkMineConstruction", 
        "name": "Think About Helping", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_mineThought", 
        "currenciesMade": [
            "thought"
        ], 
        "entityKey": "thinkMine", 
        "limitingKeys": [
            "thinkMine", 
            "thinkMineConstruction"
        ], 
        "key": "thinkMineButton", 
        "description": "makes thought"
    }, 
    "social": {
        "name": "social", 
        "key": "social", 
        "tags": [
            "social"
        ]
    }, 
    "becomeCriticalButton": {
        "constructionKey": "becomeCriticalGoalConstruction", 
        "name": "Become Critical", 
        "image": "goal_mineFrustration-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "becomeCriticalGoal", 
        "key": "becomeCriticalButton", 
        "description": "Requires cruelty."
    }, 
    "probedProblemDeposit": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Probed Problem", 
        "key": "probedProblemDeposit", 
        "deposit": {
            "probedProblem": 3
        }
    }, 
    "tryForConnectionYouMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Try For Connection", 
        "key": "tryForConnectionYouMenu"
    }, 
    "viceFlatYouMineConstruction": {
        "key": "viceFlatYouMineConstruction", 
        "constructionIdentifier": "viceFlatYouMine", 
        "name": "Vice", 
        "image": "tower_memoryRing-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Vice"
    }, 
    "sadnessMap": {
        "startManagedEntities": [
            "painMine"
        ], 
        "emotionToMap": "sadness", 
        "emotionMappedEntities": [
            "needPainButton"
        ], 
        "key": "sadnessMap"
    }, 
    "criticism": {
        "name": "criticism", 
        "key": "criticism", 
        "tags": [
            "criticism"
        ]
    }, 
    "connectHurtButton": {
        "constructionKey": "connectHurtGoalConstruction", 
        "name": "Connect To Your Hurt", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "connectHurtGoal", 
        "key": "connectHurtButton", 
        "description": "Requires will."
    }, 
    "defineHelpButton": {
        "constructionKey": "defineHelpGoalConstruction", 
        "name": "Define Yourself as Helpful", 
        "image": "goal_heart-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "defineHelpGoal", 
        "key": "defineHelpButton", 
        "description": "Requires insecurity, thought."
    }, 
    "criticismFlat": {
        "resourceCount": 1, 
        "name": "Criticism", 
        "image": "tower_eyeTear", 
        "destination": "himself", 
        "key": "criticismFlat", 
        "emotionTags": [
            "sadness"
        ], 
        "resourceKeys": "criticismMed", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "flashback_angerConstruction": {
        "key": "flashback_angerConstruction", 
        "constructionIdentifier": "flashback_anger", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "flashback_oldFailMedConstruction": {
        "key": "flashback_oldFailMedConstruction", 
        "constructionIdentifier": "flashback_oldFailMed", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "minorInterruptGoal": {
        "key": "minorInterruptGoal", 
        "randomPosition": 1, 
        "name": "Interrupt Partner", 
        "image": "goal_mineFrustration-000000", 
        "currencyRequested": {
            "distraction": 1
        }, 
        "entitiesToMake": "interruptionSwarm", 
        "goalMenuKey": "minorInterruptMenu", 
        "timeToDeath": 30
    }, 
    "reinforceComplimentMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Reinforce Other's Compliment", 
        "key": "reinforceComplimentMenu"
    }, 
    "talkInterestingMenu": {
        "image": "goal_goalAskOut-000000", 
        "name": "COMPLETED - Talk of Interesting Things", 
        "key": "talkInterestingMenu"
    }, 
    "switchSupportCrisisButton": {
        "entitiesToMake": "supportCrisisButton", 
        "key": "switchSupportCrisisButton"
    }, 
    "opennessTower": {
        "image": "tower_openDoor", 
        "activeImage": "tower_openDoor_activeOutline-0099ff", 
        "name": "Be Open", 
        "key": "opennessTower", 
        "description": "Converts will -> openness"
    }, 
    "pushInsecurityButton": {
        "constructionKey": "pushInsecurityGoalConstruction", 
        "name": "Push Insecurity", 
        "image": "goal_drive-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "pushInsecurityGoal", 
        "key": "pushInsecurityButton", 
        "interactionKeys": [
            "self"
        ], 
        "description": [
            "Requires social, insecurity.", 
            "Makes calm."
        ]
    }, 
    "resentMed": {
        "emotion": "anger", 
        "name": "resentment", 
        "image": "creepLarge-ff0000", 
        "memoryImage": "memoryAnger", 
        "health": 60, 
        "key": "resentMed"
    }, 
    "flashback_joyConstruction": {
        "key": "flashback_joyConstruction", 
        "constructionIdentifier": "flashback_joy", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "insecurePathHurting": {
        "startKey": "insecure", 
        "endKey": "hurting", 
        "key": "insecurePathHurting"
    }, 
    "calmnessAction": {
        "currenciesRequired": [
            "calm"
        ], 
        "towerKey": "calmnessTower", 
        "name": "Calm", 
        "key": "calmnessAction"
    }, 
    "giveInButton": {
        "constructionKey": "giveInGoalConstruction", 
        "name": "Give In To Hurt", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "giveInGoal", 
        "key": "giveInButton", 
        "description": "Requires pain."
    }, 
    "criticismTower": {
        "image": "tower_mineFrustration", 
        "activeImage": "tower_mineFrustration_activeOutline-0099ff", 
        "name": "Criticize", 
        "key": "criticismTower", 
        "description": "Converts completeWork + cruelty -> criticism"
    }, 
    "defineRoleBranch": {
        "flagToCheck": "defineRoleDone", 
        "key": "defineRoleBranch", 
        "notFlagEntities": "defineRoleButton"
    }, 
    "stateButton": {
        "constructionKey": "stateTowerConstruction", 
        "name": "Statement", 
        "image": "tower_newNote", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "stateTower", 
        "limitingKeys": [
            "stateTower", 
            "stateTowerConstruction"
        ], 
        "key": "stateButton", 
        "subPanel": "Towers", 
        "description": "Converts social -> state"
    }, 
    "talkAboutYouGoal": {
        "key": "talkAboutYouGoal", 
        "randomPosition": 0, 
        "name": "Talk About You", 
        "image": "goal_newNote-000000", 
        "currencyRequested": {
            "youInfo": 3, 
            "social": 3
        }, 
        "entitiesToMake": "calmnessDeposit", 
        "goalMenuKey": "talkAboutYouMenu"
    }, 
    "deriveWorkTopicButton": {
        "constructionKey": "deriveWorkTopicGoalConstruction", 
        "name": "Derive Work Points", 
        "image": "goal_towerThinkAbout-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "deriveWorkTopicGoal", 
        "key": "deriveWorkTopicButton", 
        "description": [
            "Requires will.", 
            "Makes work topic."
        ]
    }, 
    "accuseSelfishGoalConstruction": {
        "key": "accuseSelfishGoalConstruction", 
        "constructionIdentifier": "accuseSelfishGoal", 
        "name": "Constructing - Accuse of Selfishness", 
        "image": "trait-aaaaaa99_goal_goalAskAbout-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Accuse of Selfishness", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "acceptConnectionHimMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Accept Connection", 
        "key": "acceptConnectionHimMenu"
    }, 
    "obsessHimTowerConstruction": {
        "key": "obsessHimTowerConstruction", 
        "constructionIdentifier": "obsessHimTower", 
        "name": "Constructing - Obsess About Him", 
        "image": "trait-aaaaaa99_tower_hook", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Obsess About Him", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "niceMenu": {
        "image": "goal_towerFlirt-000000", 
        "name": "COMPLETED - Be Nice To You", 
        "key": "niceMenu"
    }, 
    "memory_worthlessFeel": {
        "image": "trait-013d70", 
        "memoryEmotions": [
            "sadness"
        ], 
        "key": "memory_worthlessFeel", 
        "name": "Feel Worthless"
    }, 
    "overcomeCrisisGoal": {
        "key": "overcomeCrisisGoal", 
        "randomPosition": 0, 
        "name": "Overcome Crisis", 
        "image": "goal_motivation-000000", 
        "currencyRequested": {
            "resolve": 3
        }, 
        "entitiesToMake": "faithCrisisToHisWork", 
        "goalMenuKey": "overcomeCrisisMenu"
    }, 
    "helpValueTower": {
        "image": "tower_trophy", 
        "activeImage": "tower_trophy_activeOutline-0099ff", 
        "name": "Value From Help", 
        "key": "helpValueTower", 
        "description": "Converts helped -> value"
    }, 
    "makeCriticismSwarmMenu": {
        "image": "goal_mineFrustration-000000", 
        "name": "COMPLETED - Make Swarm of Criticisms", 
        "key": "makeCriticismSwarmMenu"
    }, 
    "socialTower": {
        "image": "tower_mineSocial", 
        "activeImage": "tower_mineSocial_activeOutline-0099ff", 
        "name": "Social", 
        "key": "socialTower", 
        "description": "Converts openness -> social"
    }, 
    "slowWork": {
        "name": "slow work", 
        "key": "slowWork", 
        "tags": [
            "slowWork"
        ]
    }, 
    "calm": {
        "name": "calm", 
        "key": "calm", 
        "tags": [
            "calm"
        ]
    }, 
    "memory": {
        "mapSpawnKey": "memoryExtension", 
        "maxLevel": 6, 
        "playerKillable": "true", 
        "timeToDeath": 150
    }, 
    "diveHurtButton": {
        "constructionKey": "diveHurtGoalConstruction", 
        "name": "Submerge In Hurt", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "diveHurtGoal", 
        "key": "diveHurtButton", 
        "description": "Requires will."
    }, 
    "diveHurtGoal": {
        "key": "diveHurtGoal", 
        "randomPosition": 0, 
        "name": "Submerge In Hurt", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": "oldHurt", 
        "goalMenuKey": "diveHurtMenu"
    }, 
    "oldEmo": {
        "youKeys": "oldHurt", 
        "key": "oldEmo", 
        "himKeys": "oldFailSwarm"
    }, 
    "clever": {
        "sector": [
            4, 
            0
        ], 
        "name": "Clever Friend", 
        "aliveEntities": {
            "casualEmo": 3
        }, 
        "image": "trait-668a02", 
        "personHeld": "friend", 
        "isaacEntities": [
            "talkInterestingButton", 
            "getFeedbackButton"
        ], 
        "key": "clever", 
        "interactionKeys": [
            "himself"
        ], 
        "maxLevel": 6
    }, 
    "getOverGoodWorkMenu": {
        "image": "goal_weight-000000", 
        "name": "COMPLETED - Get Over Good Work", 
        "key": "getOverGoodWorkMenu"
    }, 
    "calmPartnerGoal": {
        "key": "calmPartnerGoal", 
        "randomPosition": 0, 
        "name": "Calm Partner", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "support": 3
        }, 
        "entitiesToMake": "switchCalmnessDeposit", 
        "goalMenuKey": "calmPartnerMenu"
    }, 
    "acceptMeanlessButton": {
        "constructionKey": "acceptMeanlessGoalConstruction", 
        "name": "Accept Meaninglessness", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "acceptMeanlessGoal", 
        "key": "acceptMeanlessButton", 
        "description": "Requires insecurity."
    }, 
    "appreciateWorkMenu": {
        "image": "goal_towerFlirt-000000", 
        "name": "COMPLETED - Appreciate His Work", 
        "key": "appreciateWorkMenu"
    }, 
    "flirtYouGoal": {
        "key": "flirtYouGoal", 
        "randomPosition": 0, 
        "name": "Flirt", 
        "image": "goal_heart-000000", 
        "currencyRequested": {
            "flirtation": 1
        }, 
        "entitiesToMake": "partnerInfoDeposit", 
        "goalMenuKey": "flirtYouMenu", 
        "description": "He's so responsive, but also so very guarded."
    }, 
    "guiltMed": {
        "emotion": "sadness", 
        "name": "guilt", 
        "image": "creepLarge-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 60, 
        "key": "guiltMed"
    }, 
    "warm": {
        "sector": [
            0, 
            0
        ], 
        "name": "Warm Friend", 
        "image": "trait-ed9933", 
        "personHeld": "friend", 
        "isaacEntities": [
            "calmnessMineButton", 
            "fishComplimentsButton"
        ], 
        "key": "warm", 
        "interactionKeys": [
            "self"
        ], 
        "maxLevel": 6
    }, 
    "goodnessMineButton": {
        "constructionKey": "goodnessMineConstruction", 
        "name": "Goodness", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_newNote", 
        "currenciesMade": [
            "goodness"
        ], 
        "entityKey": "goodnessMine", 
        "limitingKeys": [
            "goodnessMine", 
            "goodnessMineConstruction"
        ], 
        "key": "goodnessMineButton", 
        "description": "makes goodness"
    }, 
    "impulse": {
        "tags": [
            "impulse"
        ], 
        "name": "impulse", 
        "key": "impulse", 
        "checkDayEnd": 1
    }, 
    "towerHelpInfoPanel": {
        "components": [
            "towerComponent", 
            "resourceComponent", 
            "constructionComponent"
        ], 
        "helpLines": [
            "These are the activities that you can perform.", 
            "Activating them will generate the appropriate currency and may require a currency of its own."
        ], 
        "name": "Towers", 
        "key": "towerHelpInfoPanel"
    }, 
    "complimentTowerConstruction": {
        "key": "complimentTowerConstruction", 
        "constructionIdentifier": "complimentTower", 
        "name": "Constructing - Compliment", 
        "image": "trait-aaaaaa99_tower_newNote", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Compliment", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "diveHurtMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Submerge In Hurt", 
        "key": "diveHurtMenu"
    }, 
    "conversation_ext": {
        "personHeld": "relation", 
        "image": [
            "trait-cc9900", 
            "trait-B78900", 
            "trait-E0A800"
        ], 
        "name": "Full Conversation", 
        "key": "conversation_ext", 
        "sourceKey": "conversation"
    }, 
    "spendTimeMenu": {
        "image": "goal_goalBuyTime-000000", 
        "name": "COMPLETED - Spend Some Time", 
        "key": "spendTimeMenu"
    }, 
    "reinforceStupidGoal": {
        "key": "reinforceStupidGoal", 
        "randomPosition": 1, 
        "name": "Reinforce Stupidity", 
        "image": "goal_mineFrustration-000000", 
        "currencyRequested": {
            "stupid": 1
        }, 
        "entitiesToMake": "stupidFlat", 
        "goalMenuKey": "reinforceStupidMenu", 
        "timeToDeath": 30
    }, 
    "startRelationHimMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Start Relationship", 
        "key": "startRelationHimMenu"
    }, 
    "solveProbeButton": {
        "constructionKey": "solveProbeTowerConstruction", 
        "name": "Solve Probed Problems", 
        "image": "tower_newNote", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "solveProbeTower", 
        "limitingKeys": [
            "solveProbeTower", 
            "solveProbeTowerConstruction"
        ], 
        "key": "solveProbeButton", 
        "subPanel": "Towers", 
        "description": [
            "It works for you, it should work for him.", 
            "Converts probed problem -> activity"
        ]
    }, 
    "startRelationYouGoalConstruction": {
        "key": "startRelationYouGoalConstruction", 
        "constructionIdentifier": "startRelationYouGoal", 
        "name": "Constructing - Start Relationship", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Start Relationship", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "warmPathRelationship": {
        "startKey": "warm", 
        "endKey": "relationship", 
        "key": "warmPathRelationship"
    }, 
    "calmnessButton": {
        "constructionKey": "calmnessTowerConstruction", 
        "maxTowerCount": 1, 
        "name": "Calmness", 
        "image": "tower_wave", 
        "entityCost": {
            "calm": 5
        }, 
        "entityKey": "calmnessTower", 
        "limitingKeys": [
            "calmnessTower", 
            "calmnessTowerConstruction"
        ], 
        "key": "calmnessButton", 
        "subPanel": "Defenses", 
        "description": "Uses calm to calm anger, joy, sadness"
    }, 
    "supportNeedAction": {
        "currenciesRequired": [
            "need"
        ], 
        "towerKey": "supportNeedTower", 
        "currenciesToMake": [
            "support"
        ], 
        "name": "Support", 
        "key": "supportNeedAction"
    }, 
    "flashback_casualSmall": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_casualSmall", 
        "emotionTags": "casualSmall", 
        "resourceKeys": [
            "casualSmall"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes casualSmall"
    }, 
    "tryNewMenu": {
        "image": "goal_spark-000000", 
        "name": "COMPLETED - Try Something New", 
        "key": "tryNewMenu"
    }, 
    "shameBurstMine": {
        "resourceCount": 1, 
        "name": "Burst of Shame", 
        "image": "tower_memoryShame-000000", 
        "key": "shameBurstMine", 
        "emotionTags": [
            "sadness", 
            "self", 
            "worthlessSmall"
        ], 
        "resourceKeys": [
            "worthlessSmall"
        ], 
        "activeImage": "tower_memoryShame-000000_activeOutline-0099ff", 
        "description": "makes worthlessSmall"
    }, 
    "takeConnectMenu": {
        "image": "goal_goalMeetNewPerson-000000", 
        "name": "COMPLETED - Take Friend's Connection", 
        "key": "takeConnectMenu"
    }, 
    "relationship_ext": {
        "personHeld": "relation", 
        "image": [
            "trait-ffcc00", 
            "trait-E5B700", 
            "trait-FFE000"
        ], 
        "name": "Relationship", 
        "key": "relationship_ext", 
        "sourceKey": "relationship"
    }, 
    "hisGoodWork_ext": {
        "personHeld": "him", 
        "image": [
            "trait-9966ff", 
            "trait-895BE5", 
            "trait-A870FF"
        ], 
        "name": "His Good Work", 
        "key": "hisGoodWork_ext", 
        "sourceKey": "hisGoodWork"
    }, 
    "aloneMed": {
        "emotion": "sadness", 
        "name": "feeling alone", 
        "image": "creepLarge-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 60, 
        "key": "aloneMed"
    }, 
    "indulgeViceGoalConstruction": {
        "key": "indulgeViceGoalConstruction", 
        "constructionIdentifier": "indulgeViceGoal", 
        "name": "Constructing - Indulge Vice", 
        "image": "trait-aaaaaa99_goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Indulge Vice", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "switchThankGoal": {
        "entitiesToMake": "thankGoal", 
        "key": "switchThankGoal"
    }, 
    "exploreStrengthButton": {
        "constructionKey": "exploreStrengthGoalConstruction", 
        "name": "Explore His Strength", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "exploreStrengthGoal", 
        "key": "exploreStrengthButton", 
        "description": "Requires support."
    }, 
    "makeComplimentSwarmMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Make Swarm of Compliments", 
        "key": "makeComplimentSwarmMenu"
    }, 
    "startRelationHimButton": {
        "aiVal": 5, 
        "constructionKey": "startRelationHimGoalConstruction", 
        "name": "Start Relationship", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "startRelationHimGoal", 
        "key": "startRelationHimButton", 
        "interactionKeys": [
            "himself"
        ], 
        "description": "Requires will."
    }, 
    "busyWorkPlaced": {
        "y": 23, 
        "x": 13, 
        "tower": "busyWorkTower", 
        "key": "busyWorkPlaced"
    }, 
    "completeWork": {
        "name": "completeWork", 
        "key": "completeWork", 
        "tags": [
            "completeWork"
        ]
    }, 
    "winGoal": {
        "key": "winGoal", 
        "randomPosition": 0, 
        "name": "Win Game!", 
        "image": "goal_trophy-000000", 
        "currencyRequested": {
            "hisEmotion": 1
        }, 
        "entitiesToMake": "gameEnd", 
        "goalMenuKey": "winMenu", 
        "description": [
            "If you can get him to feel emotion, then you can feel you did", 
            "something"
        ]
    }, 
    "hundredHealthComponent": {
        "health": 100
    }, 
    "quietCriticismMenu": {
        "image": "goal_goalCalmDown-000000", 
        "name": "COMPLETED - Quiet Criticism of Self", 
        "key": "quietCriticismMenu"
    }, 
    "completeWorkGoal": {
        "key": "completeWorkGoal", 
        "randomPosition": 0, 
        "name": "Complete Work", 
        "image": "goal_trophy-000000", 
        "currencyRequested": {
            "goodWork": 3
        }, 
        "entitiesToMake": "completeWorkResult", 
        "goalMenuKey": "completeWorkMenu"
    }, 
    "topic": {
        "name": "topic", 
        "key": "topic", 
        "tags": [
            "topic"
        ]
    }, 
    "currency": {
        "planeOfExistence": "path"
    }, 
    "makeStupidityFlatGoalConstruction": {
        "key": "makeStupidityFlatGoalConstruction", 
        "constructionIdentifier": "makeStupidityFlatGoal", 
        "name": "Constructing - Make Statement About Stupidity", 
        "image": "trait-aaaaaa99_goal_mineFrustration-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Make Statement About Stupidity", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "tryForConnectionYouGoal": {
        "key": "tryForConnectionYouGoal", 
        "randomPosition": 0, 
        "name": "Try For Connection", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "partnerInfo": 3
        }, 
        "entitiesToMake": "acceptConnectionHimGoal", 
        "goalMenuKey": "tryForConnectionYouMenu"
    }, 
    "flashback_viceMed": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_viceMed", 
        "emotionTags": "viceMed", 
        "resourceKeys": [
            "viceMed"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes viceMed"
    }, 
    "spendTimeButton": {
        "constructionKey": "spendTimeGoalConstruction", 
        "name": "Spend Some Time", 
        "image": "goal_goalBuyTime-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "spendTimeGoal", 
        "key": "spendTimeButton", 
        "interactionKeys": 1, 
        "description": "Requires relationship time."
    }, 
    "startRelationHimGoal": {
        "key": "startRelationHimGoal", 
        "randomPosition": 0, 
        "name": "Start Relationship", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": [
            "relationBranch", 
            "restlessPathNewRelationship", 
            "setHimRelation", 
            "killStartRelationHimButton"
        ], 
        "goalMenuKey": "startRelationHimMenu"
    }, 
    "completeWorkButton": {
        "aiVal": 5, 
        "constructionKey": "completeWorkGoalConstruction", 
        "name": "Complete Work", 
        "image": "goal_trophy-000000", 
        "description": "Requires goodWork.", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "completeWorkGoal", 
        "key": "completeWorkButton", 
        "interactionKeys": [
            "himself"
        ], 
        "displayRiskIcon": 1
    }, 
    "askAboutRestlessGoalConstruction": {
        "key": "askAboutRestlessGoalConstruction", 
        "constructionIdentifier": "askAboutRestlessGoal", 
        "name": "Constructing - Ask About Restlessness", 
        "image": "trait-aaaaaa99_goal_goalAskAbout-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Ask About Restlessness", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "overcomeHurtButton": {
        "constructionKey": "overcomeHurtGoalConstruction", 
        "name": "Overcome Hurt", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "overcomeHurtGoal", 
        "key": "overcomeHurtButton", 
        "description": "Requires calm."
    }, 
    "startRelationYouGoal": {
        "key": "startRelationYouGoal", 
        "randomPosition": 0, 
        "name": "Start Relationship", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "openness": 3
        }, 
        "entitiesToMake": [
            "relationBranch", 
            "worthlessPathNewRelationship", 
            "setYouRelation", 
            "killStartRelationYouButton", 
            "worthlessToInsecurity", 
            "valueDeposit"
        ], 
        "goalMenuKey": "startRelationYouMenu", 
        "description": "He's new and exciting, but why does he look so sad?"
    }, 
    "beSupportedButton": {
        "constructionKey": "beSupportedGoalConstruction", 
        "name": "Take Support", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "beSupportedGoal", 
        "key": "beSupportedButton", 
        "description": "Requires support."
    }, 
    "joy": {
        "emotion": "joy", 
        "name": "joy", 
        "image": "creep-ffff00", 
        "memoryImage": "memoryJoy", 
        "health": 10, 
        "key": "joy"
    }, 
    "callousnessTowerConstruction": {
        "key": "callousnessTowerConstruction", 
        "constructionIdentifier": "callousnessTower", 
        "name": "Constructing - Callousness", 
        "image": "trait-aaaaaa99_tower_numb", 
        "currencyRequested": {
            "selfishness": 5
        }, 
        "constructionName": "Callousness", 
        "killOnTransform": 0
    }, 
    "hurtingPathRelationship": {
        "startKey": "hurting", 
        "endKey": "relationship", 
        "key": "hurtingPathRelationship"
    }, 
    "good_ext": {
        "personHeld": "good", 
        "image": [
            "trait-ccffcc", 
            "trait-B7E5B7", 
            "trait-E0FFE0"
        ], 
        "name": "Self-Sacrificing", 
        "key": "good_ext", 
        "sourceKey": "good"
    }, 
    "getFeedbackButton": {
        "constructionKey": "getFeedbackGoalConstruction", 
        "name": "Get Feedback", 
        "image": "goal_hook-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "getFeedbackGoal", 
        "key": "getFeedbackButton", 
        "description": "Requires work topic, will."
    }, 
    "makeSlowWorkSwarmGoal": {
        "key": "makeSlowWorkSwarmGoal", 
        "randomPosition": 0, 
        "name": "Make Swarm About Slow Work", 
        "image": "goal_mineFrustration-000000", 
        "currencyRequested": {
            "slowWork": 3, 
            "swarm": 3
        }, 
        "entitiesToMake": "slowWorkSwarm", 
        "goalMenuKey": "makeSlowWorkSwarmMenu"
    }, 
    "cheerMineButton": {
        "constructionKey": "cheerMineConstruction", 
        "name": "Cheer Mine", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_mineCheer", 
        "currenciesMade": [
            "cheer"
        ], 
        "entityKey": "cheerMine", 
        "limitingKeys": [
            "cheerMine", 
            "cheerMineConstruction"
        ], 
        "key": "cheerMineButton", 
        "description": "makes cheer"
    }, 
    "crueltyTowerConstruction": {
        "key": "crueltyTowerConstruction", 
        "constructionIdentifier": "crueltyTower", 
        "name": "Constructing - Cruelty", 
        "image": "trait-aaaaaa99_tower_goalDisavowal-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Cruelty", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "oldFail": {
        "name": "old failures", 
        "key": "oldFail", 
        "tags": [
            "oldFail"
        ]
    }, 
    "need": {
        "name": "need", 
        "key": "need", 
        "tags": [
            "need"
        ]
    }, 
    "solveProbeTower": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Solve Probed Problems", 
        "key": "solveProbeTower", 
        "description": [
            "It works for you, it should work for him.", 
            "Converts probed problem -> activity"
        ]
    }, 
    "obsessionDeposit": {
        "image": "tower_motivation", 
        "activeImage": "tower_motivation_activeOutline-0099ff", 
        "name": "Obsession", 
        "key": "obsessionDeposit", 
        "deposit": {
            "obsession": 3
        }
    }, 
    "makeComplimentFlatGoalConstruction": {
        "key": "makeComplimentFlatGoalConstruction", 
        "constructionIdentifier": "makeComplimentFlatGoal", 
        "name": "Constructing - Make Complimentary Statement", 
        "image": "trait-aaaaaa99_goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Make Complimentary Statement", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "allowWeaknessGoal": {
        "key": "allowWeaknessGoal", 
        "randomPosition": 0, 
        "name": "Allow Yourself Weakness", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "support": 3
        }, 
        "entitiesToMake": "flipHurt", 
        "goalMenuKey": "allowWeaknessMenu"
    }, 
    "casualSmall": {
        "emotion": "anger", 
        "name": "casual cruelty", 
        "image": "creep-ff0000", 
        "memoryImage": "memoryAnger", 
        "health": 20, 
        "key": "casualSmall"
    }, 
    "tryNewButton": {
        "constructionKey": "tryNewGoalConstruction", 
        "name": "Try Something New", 
        "image": "goal_spark-000000", 
        "description": "Requires will.", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "tryNewGoal", 
        "disablingEntities": [
            "exploreNewGoal"
        ], 
        "key": "tryNewButton", 
        "displayRiskIcon": 1
    }, 
    "insecure": {
        "name": "insecurity", 
        "key": "insecure", 
        "tags": [
            "insecure"
        ]
    }, 
    "feelUselessGoalConstruction": {
        "key": "feelUselessGoalConstruction", 
        "constructionIdentifier": "feelUselessGoal", 
        "name": "Constructing - Feel Useless", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Feel Useless", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "flashback_worthlessSmall": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_worthlessSmall", 
        "emotionTags": "worthlessSmall", 
        "resourceKeys": [
            "worthlessSmall"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes worthlessSmall"
    }, 
    "selfishPathHim": {
        "startKey": "selfish", 
        "endKey": "him", 
        "key": "selfishPathHim"
    }, 
    "learnHistoryMenu": {
        "image": "goal_goalAskAbout-000000", 
        "name": "COMPLETED - Learn His History", 
        "key": "learnHistoryMenu"
    }, 
    "takeOutFrustrationGoalConstruction": {
        "key": "takeOutFrustrationGoalConstruction", 
        "constructionIdentifier": "takeOutFrustrationGoal", 
        "name": "Constructing - Take Out Frustrations", 
        "image": "trait-aaaaaa99_goal_mineFrustration-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Take Out Frustrations", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "selfishnessMineConstruction": {
        "key": "selfishnessMineConstruction", 
        "constructionIdentifier": "selfishnessMine", 
        "name": "Constructing - Selfishness", 
        "image": "trait-aaaaaa99_tower_depositSin", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Selfishness", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "slowWorkSmall": {
        "emotion": "anger", 
        "name": "slow work", 
        "image": "creep-ff0000", 
        "memoryImage": "memoryAnger", 
        "health": 20, 
        "key": "slowWorkSmall"
    }, 
    "oldFailMed": {
        "emotion": "sadness", 
        "name": "old failures", 
        "image": "creepLarge-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 60, 
        "key": "oldFailMed"
    }, 
    "connectHurtBranch": {
        "flagToCheck": "connectHurtDone", 
        "key": "connectHurtBranch", 
        "notFlagEntities": "connectHurtButton"
    }, 
    "criticizeSelfGoalConstruction": {
        "key": "criticizeSelfGoalConstruction", 
        "constructionIdentifier": "criticizeSelfGoal", 
        "name": "Constructing - Criticize Yourself", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Criticize Yourself", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "clearNewRelationship": {
        "trait": "newRelationship", 
        "key": "clearNewRelationship"
    }, 
    "criticizeSelfGoal": {
        "key": "criticizeSelfGoal", 
        "randomPosition": 0, 
        "name": "Criticize Yourself", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 1
        }, 
        "entitiesToMake": [
            "crueltyToInsecurity", 
            "insecureSwarmYou"
        ], 
        "goalMenuKey": "criticizeSelfMenu"
    }, 
    "makeCriticismSwarmButton": {
        "constructionKey": "makeCriticismSwarmGoalConstruction", 
        "name": "Make Swarm of Criticisms", 
        "image": "goal_mineFrustration-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeCriticismSwarmGoal", 
        "key": "makeCriticismSwarmButton", 
        "description": "Requires swarm, criticism."
    }, 
    "meditativeMineConstruction": {
        "key": "meditativeMineConstruction", 
        "constructionIdentifier": "meditativeMine", 
        "name": "Constructing - Meditation", 
        "image": "trait-aaaaaa99_tower_goalCalmDown-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Meditation", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "defineRoleMenu": {
        "image": "goal_puzzle-000000", 
        "completeText": "Things are just a little clearer now.", 
        "name": "COMPLETED - Define Roles", 
        "key": "defineRoleMenu"
    }, 
    "makeDreamDeathMajorGoalConstruction": {
        "key": "makeDreamDeathMajorGoalConstruction", 
        "constructionIdentifier": "makeDreamDeathMajorGoal", 
        "name": "Constructing - Talk About Death of Dream", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Talk About Death of Dream", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "explainSpendTimeFail": {
        "completeText": "It was a talk, but not a very memorable one.", 
        "key": "explainSpendTimeFail"
    }, 
    "quietTimeGoal": {
        "key": "quietTimeGoal", 
        "randomPosition": 0, 
        "name": "Quiet Time Together", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "social": 6
        }, 
        "entitiesToMake": {
            "calmnessDeposit": 100, 
            "youInfoDeposit": 50
        }, 
        "goalMenuKey": "quietTimeMenu"
    }, 
    "tryForConnectionHimGoal": {
        "key": "tryForConnectionHimGoal", 
        "randomPosition": 0, 
        "name": "Try For Connection", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "youInfo": 3
        }, 
        "entitiesToMake": "acceptConnectionYouGoal", 
        "goalMenuKey": "tryForConnectionHimMenu"
    }, 
    "angerMap": {
        "startManagedEntities": [
            "frustrationMine"
        ], 
        "emotionToMap": "anger", 
        "emotionMappedEntities": [
            "nullEntity"
        ], 
        "key": "angerMap"
    }, 
    "spendTimeCleverGoalConstruction": {
        "key": "spendTimeCleverGoalConstruction", 
        "constructionIdentifier": "spendTimeCleverGoal", 
        "name": "Constructing - Spend Time", 
        "image": "trait-aaaaaa99_goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Spend Time", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "calmnessDeposit": {
        "randomPosition": 1, 
        "name": "Calmness", 
        "image": "tower_wave", 
        "deposit": {
            "calm": 3
        }, 
        "key": "calmnessDeposit", 
        "activeImage": "tower_wave_activeOutline-0099ff"
    }, 
    "makeOldFailFlatMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Make Statement of Old Failures", 
        "key": "makeOldFailFlatMenu"
    }, 
    "helpGoal": {
        "key": "helpGoal", 
        "randomPosition": 1, 
        "name": "Help", 
        "makeOnTimeOut": "guiltEmo", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "cheer": 3
        }, 
        "entitiesToMake": "switchValueDeposit", 
        "goalMenuKey": "helpMenu", 
        "timeToDeath": 150
    }, 
    "explainLearnHimFail": {
        "completeText": "Sometimes you can talk and talk and just learn nothing new.", 
        "key": "explainLearnHimFail"
    }, 
    "worthlessFeel": {
        "emotionsToAdd": {
            "worthlessMed": 1
        }, 
        "name": "Feel Worthless", 
        "image": "tower_eyeTear", 
        "key": "worthlessFeel", 
        "memoryKey": "memory_worthlessFeel", 
        "emotionTags": [
            "sadness", 
            "self"
        ], 
        "resourceKey": "worthlessFeelMineConstruction", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "busyWorkAction": {
        "currenciesRequired": [
            "busyWork"
        ], 
        "towerKey": "busyWorkTower", 
        "name": "Busy Work", 
        "key": "busyWorkAction"
    }, 
    "calmnessTowerConstruction": {
        "key": "calmnessTowerConstruction", 
        "constructionIdentifier": "calmnessTower", 
        "name": "Constructing - Calmness", 
        "image": "trait-aaaaaa99_tower_wave", 
        "currencyRequested": {
            "calm": 5
        }, 
        "constructionName": "Calmness", 
        "killOnTransform": 0
    }, 
    "slowWorkDeposit": {
        "randomPosition": 1, 
        "timeToDeath": 120, 
        "image": "tower_towerThinkAbout", 
        "sourceTrait": "hisWork", 
        "deposit": {
            "slowWork": 3
        }, 
        "key": "slowWorkDeposit", 
        "activeImage": "tower_towerThinkAbout_activeOutline-0099ff", 
        "name": "Slow Work"
    }, 
    "needPainTowerConstruction": {
        "key": "needPainTowerConstruction", 
        "constructionIdentifier": "needPainTower", 
        "name": "Constructing - Need Help", 
        "image": "trait-aaaaaa99_tower_droop", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Need Help", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "majorTower": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Major Statement", 
        "key": "majorTower", 
        "description": "Converts social -> major"
    }, 
    "selfValueTowerConstruction": {
        "key": "selfValueTowerConstruction", 
        "constructionIdentifier": "selfValueTower", 
        "name": "Constructing - Valuing Yourself", 
        "image": "trait-aaaaaa99_tower_trophy", 
        "currencyRequested": {
            "value": 3
        }, 
        "constructionName": "Valuing Yourself", 
        "killOnTransform": 0
    }, 
    "hisBadWork": {
        "sector": [
            0, 
            0
        ], 
        "name": "His Bad Work", 
        "aliveEntities": {
            "himSupportGoal": 5
        }, 
        "image": "trait-3333ff", 
        "personHeld": "him", 
        "isaacEntities": [
            "getOverBadWorkButton", 
            "switchTriggerCrisisButton"
        ], 
        "key": "hisBadWork", 
        "interactionKeys": [
            "himself"
        ]
    }, 
    "interruptSmall": {
        "emotion": "anger", 
        "name": "interruption", 
        "image": "creep-ff0000", 
        "memoryImage": "memoryAnger", 
        "health": 20, 
        "key": "interruptSmall"
    }, 
    "winGoalConstruction": {
        "key": "winGoalConstruction", 
        "constructionIdentifier": "winGoal", 
        "name": "Constructing - Win Game!", 
        "image": "trait-aaaaaa99_goal_trophy-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Win Game!", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "makeOldFailSwarmMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Make Swarm About Old Failures", 
        "key": "makeOldFailSwarmMenu"
    }, 
    "memory_insecureSwarmYou": {
        "image": "trait-013d70", 
        "memoryEmotions": [
            "sadness"
        ], 
        "key": "memory_insecureSwarmYou", 
        "name": "Insecurities"
    }, 
    "sadAttackMineConstruction": {
        "key": "sadAttackMineConstruction", 
        "constructionIdentifier": "sadAttackMine", 
        "name": "Sadness Burst", 
        "image": "tower_pain-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Sadness Burst"
    }, 
    "obsessHimButton": {
        "constructionKey": "obsessHimTowerConstruction", 
        "name": "Obsess About Him", 
        "image": "tower_hook", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "obsessHimTower", 
        "limitingKeys": [
            "obsessHimTower", 
            "obsessHimTowerConstruction"
        ], 
        "key": "obsessHimButton", 
        "subPanel": "Towers", 
        "description": "Converts Info on Partner -> obsession"
    }, 
    "shareJoyButton": {
        "constructionKey": "shareJoyTowerConstruction", 
        "maxTowerCount": 1, 
        "name": "Sharing Joy", 
        "image": "tower_mineCheer", 
        "entityCost": {
            "social": 5
        }, 
        "entityKey": "shareJoyTower", 
        "limitingKeys": [
            "shareJoyTower", 
            "shareJoyTowerConstruction"
        ], 
        "key": "shareJoyButton", 
        "subPanel": "Defenses", 
        "description": "Uses social to calm joy"
    }, 
    "choreGoal": {
        "key": "choreGoal", 
        "randomPosition": 1, 
        "name": "Chores", 
        "makeOnTimeOut": "shameBurst", 
        "image": "goal_goalPayRent-000000", 
        "description": [
            "Chores for work, chores for the house. Chores for everything that's", 
            "not fun."
        ], 
        "sourceTrait": "restLife", 
        "currencyRequested": {
            "will": 3
        }, 
        "goalMenuKey": "choreMenu", 
        "interactionKeys": [
            "self"
        ], 
        "timeToDeath": 150
    }, 
    "connectFriendsGoalConstruction": {
        "key": "connectFriendsGoalConstruction", 
        "constructionIdentifier": "connectFriendsGoal", 
        "name": "Constructing - Connect to Old Friends", 
        "image": "trait-aaaaaa99_goal_mineSocial-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Connect to Old Friends", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "goodPathRelationship": {
        "startKey": "good", 
        "endKey": "relationship", 
        "key": "goodPathRelationship"
    }, 
    "interesting": {
        "name": "interesting", 
        "key": "interesting", 
        "tags": [
            "interesting"
        ]
    }, 
    "clever_ext": {
        "personHeld": "friend", 
        "image": [
            "trait-668a02", 
            "trait-5B7C01", 
            "trait-709702"
        ], 
        "name": "Clever Friend", 
        "key": "clever_ext", 
        "sourceKey": "clever"
    }, 
    "restlessPathStrong": {
        "startKey": "restless", 
        "endKey": "strong", 
        "key": "restlessPathStrong"
    }, 
    "criticizeSelfMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Criticize Yourself", 
        "key": "criticizeSelfMenu"
    }, 
    "guiltEmoFlat": {
        "resourceCount": 1, 
        "name": "Guilt", 
        "image": "tower_eyeTear", 
        "destination": "himself", 
        "key": "guiltEmoFlat", 
        "emotionTags": [
            "sadness"
        ], 
        "resourceKeys": "guiltMed", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "openResponseGoal": {
        "key": "openResponseGoal", 
        "randomPosition": 1, 
        "name": "Open Response", 
        "image": "goal_towerFlirt-000000", 
        "currencyRequested": {
            "openness": 1
        }, 
        "entitiesToMake": "youInfoDeposit", 
        "goalMenuKey": "openResponseMenu", 
        "timeToDeath": 60
    }, 
    "tryForConnectionYouButton": {
        "constructionKey": "tryForConnectionYouGoalConstruction", 
        "name": "Try For Connection", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "tryForConnectionYouGoal", 
        "key": "tryForConnectionYouButton", 
        "interactionKeys": [
            "self"
        ], 
        "description": "Requires Info on Partner."
    }, 
    "talkInterestingGoal": {
        "key": "talkInterestingGoal", 
        "randomPosition": 0, 
        "name": "Talk of Interesting Things", 
        "image": "goal_goalAskOut-000000", 
        "currencyRequested": {
            "interesting": 3
        }, 
        "goalMenuKey": "talkInterestingMenu"
    }, 
    "flashback_worthlessSmallConstruction": {
        "key": "flashback_worthlessSmallConstruction", 
        "constructionIdentifier": "flashback_worthlessSmall", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "hurting": {
        "sector": [
            0, 
            0
        ], 
        "name": "Hurting", 
        "image": "trait-660066", 
        "personHeld": "hurt", 
        "isaacEntities": [
            "sharePainButton", 
            "overcomeHurtButton"
        ], 
        "key": "hurting", 
        "interactionKeys": [
            "self"
        ], 
        "maxLevel": 6, 
        "startManagedEntities": [
            "oldFailMine", 
            "oldFailMine"
        ]
    }, 
    "good": {
        "sector": [
            0, 
            0
        ], 
        "name": "Self-Sacrificing", 
        "image": "trait-ccffcc", 
        "personHeld": "good", 
        "isaacEntities": [
            "findUsefulButton", 
            "thinkMineButton", 
            "accuseSelfishButton", 
            "needHelpButton"
        ], 
        "key": "good", 
        "interactionKeys": [
            "self"
        ], 
        "maxLevel": 6
    }, 
    "quietTimeGoalConstruction": {
        "key": "quietTimeGoalConstruction", 
        "constructionIdentifier": "quietTimeGoal", 
        "name": "Constructing - Quiet Time Together", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Quiet Time Together", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "fishComplimentsMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Fish For Compliments", 
        "key": "fishComplimentsMenu"
    }, 
    "calmPartnerMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Calm Partner", 
        "key": "calmPartnerMenu"
    }, 
    "getOverBadWorkButton": {
        "constructionKey": "getOverBadWorkGoalConstruction", 
        "name": "Get Over Bad Work", 
        "image": "goal_weight-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "getOverBadWorkGoal", 
        "key": "getOverBadWorkButton", 
        "description": "Requires will."
    }, 
    "makeSlowWorkFlatButton": {
        "constructionKey": "makeSlowWorkFlatGoalConstruction", 
        "name": "Make Statement About Slow Work", 
        "image": "goal_mineFrustration-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeSlowWorkFlatGoal", 
        "key": "makeSlowWorkFlatButton", 
        "description": "Requires state, slow work."
    }, 
    "makeSlowWorkSwarmMenu": {
        "image": "goal_mineFrustration-000000", 
        "name": "COMPLETED - Make Swarm About Slow Work", 
        "key": "makeSlowWorkSwarmMenu"
    }, 
    "viceAction": {
        "currenciesRequired": [
            "social", 
            "energy"
        ], 
        "towerKey": "viceTower", 
        "currenciesToMake": [
            "vice"
        ], 
        "name": "Vice", 
        "key": "viceAction"
    }, 
    "sadAttackMine": {
        "resourceCount": 1, 
        "name": "Sadness Burst", 
        "image": "tower_pain", 
        "key": "sadAttackMine", 
        "emotionTags": [
            "self", 
            "sadness"
        ], 
        "resourceKeys": [
            "sadness"
        ], 
        "activeImage": "tower_pain_activeOutline-0099ff", 
        "description": "makes sadness"
    }, 
    "indulgeViceMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Indulge Vice", 
        "key": "indulgeViceMenu"
    }, 
    "setYouRelation": {
        "flag": "youRelation", 
        "key": "setYouRelation"
    }, 
    "frustrationMine": {
        "image": "tower_mineFrustration", 
        "resourceKeys": [
            "frustration"
        ], 
        "name": "Frustration Mine", 
        "key": "frustrationMine", 
        "activeImage": "tower_mineFrustration_activeOutline-0099ff"
    }, 
    "gameStateEntity": {
        "name": "gameStateEntity", 
        "key": "gameStateEntity"
    }, 
    "speakOfValueGoal": {
        "key": "speakOfValueGoal", 
        "randomPosition": 0, 
        "name": "Speak of Your Value", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": "complimentFlatYou", 
        "goalMenuKey": "speakOfValueMenu"
    }, 
    "selfValueButton": {
        "constructionKey": "selfValueTowerConstruction", 
        "maxTowerCount": 1, 
        "name": "Valuing Yourself", 
        "image": "tower_trophy", 
        "entityCost": {
            "value": 3
        }, 
        "entityKey": "selfValueTower", 
        "limitingKeys": [
            "selfValueTower", 
            "selfValueTowerConstruction"
        ], 
        "key": "selfValueButton", 
        "subPanel": "Defenses", 
        "description": "Uses value to calm anger, sadness"
    }, 
    "takeSupportTower": {
        "description": "Uses support to calm anger, sadness", 
        "charges": 5, 
        "image": "tower_dependence", 
        "damage": 20, 
        "damageMultipliers": {
            "anger": 1, 
            "sadness": 1
        }, 
        "impulseTicks": 1, 
        "key": "takeSupportTower", 
        "activeImage": "tower_dependence_activeOutline-0099ff", 
        "name": "Take Support"
    }, 
    "tryForConnectionHimButton": {
        "aiVal": 5, 
        "constructionKey": "tryForConnectionHimGoalConstruction", 
        "name": "Try For Connection", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "tryForConnectionHimGoal", 
        "key": "tryForConnectionHimButton", 
        "interactionKeys": [
            "himself"
        ], 
        "description": "Requires Info on You."
    }, 
    "majorAction": {
        "currenciesRequired": [
            "social"
        ], 
        "towerKey": "majorTower", 
        "currenciesToMake": [
            "major"
        ], 
        "name": "Make Major Statement", 
        "key": "majorAction"
    }, 
    "flashback_worthlessMed": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_worthlessMed", 
        "emotionTags": "worthlessMed", 
        "resourceKeys": [
            "worthlessMed"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes worthlessMed"
    }, 
    "flirtHimGoal": {
        "key": "flirtHimGoal", 
        "randomPosition": 0, 
        "name": "Flirt", 
        "image": "goal_heart-000000", 
        "currencyRequested": {
            "flirtation": 1
        }, 
        "entitiesToMake": [
            "youInfoDeposit", 
            "complimentFlatYou"
        ], 
        "goalMenuKey": "flirtHimMenu"
    }, 
    "swarmAction": {
        "currenciesRequired": [
            "social"
        ], 
        "towerKey": "swarmTower", 
        "currenciesToMake": [
            "swarm"
        ], 
        "name": "Make Swarm", 
        "key": "swarmAction"
    }, 
    "generousAction": {
        "currenciesRequired": [
            "cheer"
        ], 
        "towerKey": "generousTower", 
        "currenciesToMake": [
            "generosity"
        ], 
        "name": "Be Generous", 
        "key": "generousAction"
    }, 
    "stateTowerConstruction": {
        "key": "stateTowerConstruction", 
        "constructionIdentifier": "stateTower", 
        "name": "Constructing - Statement", 
        "image": "trait-aaaaaa99_tower_newNote", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Statement", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "newTraitParticle": {
        "effectRadius": 30, 
        "image": "dot-ffd700", 
        "key": "newTraitParticle"
    }, 
    "truth": {
        "name": "truth", 
        "key": "truth", 
        "tags": [
            "truth"
        ]
    }, 
    "singleUseTrainPath": {
        "focusCost": 0, 
        "requiresFullPath": "false"
    }, 
    "personCurrency": {
        "planeOfExistence": "path"
    }, 
    "casualMed": {
        "emotion": "anger", 
        "name": "casual cruelty", 
        "image": "creepLarge-ff0000", 
        "memoryImage": "memoryAnger", 
        "health": 60, 
        "key": "casualMed"
    }, 
    "truthTower": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Speak Truth", 
        "key": "truthTower", 
        "description": "Converts insecurity -> truth"
    }, 
    "complimentYouMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Compliment You", 
        "key": "complimentYouMenu"
    }, 
    "overcomeHurtGoalConstruction": {
        "key": "overcomeHurtGoalConstruction", 
        "constructionIdentifier": "overcomeHurtGoal", 
        "name": "Constructing - Overcome Hurt", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Overcome Hurt", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "restless": {
        "sector": [
            0, 
            0
        ], 
        "name": "His Restlessness", 
        "image": "trait-ff66ff", 
        "personHeld": "him", 
        "isaacEntities": [
            "himRelationButtonBranch", 
            "askAboutRestlessButton", 
            "trySomethingButton"
        ], 
        "key": "restless", 
        "interactionKeys": [
            "self", 
            "himself"
        ], 
        "maxLevel": 6
    }, 
    "allowWeaknessMenu": {
        "image": "goal_dependence-000000", 
        "completeText": "Sometimes you just have to do what is easy.", 
        "name": "COMPLETED - Allow Yourself Weakness", 
        "key": "allowWeaknessMenu"
    }, 
    "spendTimeWarmMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Spend Time", 
        "key": "spendTimeWarmMenu"
    }, 
    "goodPathYou": {
        "startKey": "good", 
        "endKey": "you", 
        "key": "goodPathYou"
    }, 
    "getOverBadWorkMenu": {
        "image": "goal_weight-000000", 
        "name": "COMPLETED - Get Over Bad Work", 
        "key": "getOverBadWorkMenu"
    }, 
    "askHelpMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Ask For Help", 
        "key": "askHelpMenu"
    }, 
    "makeOldFailSwarmGoalConstruction": {
        "key": "makeOldFailSwarmGoalConstruction", 
        "constructionIdentifier": "makeOldFailSwarmGoal", 
        "name": "Constructing - Make Swarm About Old Failures", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Make Swarm About Old Failures", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "rechargeAction": {
        "currenciesRequired": [
            "cheer"
        ], 
        "towerKey": "rechargeTower", 
        "currenciesToMake": [
            "will"
        ], 
        "name": "Recharge", 
        "key": "rechargeAction"
    }, 
    "obsession": {
        "name": "obsession", 
        "key": "obsession", 
        "tags": [
            "obsession"
        ]
    }, 
    "talkInterestingButton": {
        "constructionKey": "talkInterestingGoalConstruction", 
        "name": "Talk of Interesting Things", 
        "image": "goal_goalAskOut-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "talkInterestingGoal", 
        "key": "talkInterestingButton", 
        "description": "Requires interesting."
    }, 
    "reinforceCriticismMenu": {
        "image": "goal_mineFrustration-000000", 
        "name": "COMPLETED - Reinforce Other's Criticism", 
        "key": "reinforceCriticismMenu"
    }, 
    "distractButton": {
        "constructionKey": "distractTowerConstruction", 
        "name": "Distract", 
        "image": "tower_mineCheer", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "distractTower", 
        "limitingKeys": [
            "distractTower", 
            "distractTowerConstruction"
        ], 
        "key": "distractButton", 
        "subPanel": "Towers", 
        "interactionKeys": [
            "self"
        ], 
        "description": "Converts social + need -> distraction"
    }, 
    "selfValuePlaced": {
        "y": 23, 
        "x": 13, 
        "tower": "selfValueTower", 
        "key": "selfValuePlaced"
    }, 
    "makeCriticismFlatGoal": {
        "key": "makeCriticismFlatGoal", 
        "randomPosition": 0, 
        "name": "Make Critical Statement", 
        "image": "goal_mineFrustration-000000", 
        "currencyRequested": {
            "criticism": 3, 
            "state": 3
        }, 
        "entitiesToMake": "criticismFlat", 
        "goalMenuKey": "makeCriticismFlatMenu"
    }, 
    "fishComplimentsGoal": {
        "key": "fishComplimentsGoal", 
        "randomPosition": 0, 
        "name": "Fish For Compliments", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "insecure": 3
        }, 
        "entitiesToMake": [
            "valueDeposit", 
            "complimentSwarmYou"
        ], 
        "goalMenuKey": "fishComplimentsMenu"
    }, 
    "defineHelpGoalConstruction": {
        "key": "defineHelpGoalConstruction", 
        "constructionIdentifier": "defineHelpGoal", 
        "name": "Constructing - Define Yourself as Helpful", 
        "image": "trait-aaaaaa99_goal_heart-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Define Yourself as Helpful", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "mistrustJoyAction": {
        "currenciesRequired": [
            "insecure"
        ], 
        "towerKey": "mistrustJoyTower", 
        "name": "Mistrust Joy", 
        "key": "mistrustJoyAction"
    }, 
    "selfDistractionTowerConstruction": {
        "key": "selfDistractionTowerConstruction", 
        "constructionIdentifier": "selfDistractionTower", 
        "name": "Constructing - Distracting Yourself", 
        "image": "trait-aaaaaa99_tower_mineWill", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Distracting Yourself", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "rejectMeanlessGoalConstruction": {
        "key": "rejectMeanlessGoalConstruction", 
        "constructionIdentifier": "rejectMeanlessGoal", 
        "name": "Constructing - Reject Meaninglessness", 
        "image": "trait-aaaaaa99_goal_openMind-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Reject Meaninglessness", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "loosenUpGoal": {
        "key": "loosenUpGoal", 
        "randomPosition": 1, 
        "name": "Loosen Up", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "cheer": 3
        }, 
        "entitiesToMake": "flipMature", 
        "goalMenuKey": "loosenUpMenu"
    }, 
    "hardWorkGoal": {
        "key": "hardWorkGoal", 
        "randomPosition": 0, 
        "name": "Hard Work", 
        "image": "goal_weight-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": {
            "goodWorkDeposit": 33
        }, 
        "goalMenuKey": "hardWorkMenu"
    }, 
    "feedCrisisResult": {
        "goodEntities": "crisisExplode", 
        "badEntities": "explainFeedCrisisFail", 
        "key": "feedCrisisResult"
    }, 
    "connectFriendsButton": {
        "constructionKey": "connectFriendsGoalConstruction", 
        "name": "Connect to Old Friends", 
        "image": "goal_mineSocial-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "connectFriendsGoal", 
        "key": "connectFriendsButton", 
        "description": "Requires will."
    }, 
    "opennessTowerConstruction": {
        "key": "opennessTowerConstruction", 
        "constructionIdentifier": "opennessTower", 
        "name": "Constructing - Be Open", 
        "image": "trait-aaaaaa99_tower_openDoor", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Be Open", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "crueltyToInsecurity": {
        "sourceTrait": "cruelty", 
        "newTrait": "insecurity", 
        "key": "crueltyToInsecurity"
    }, 
    "spendTimeCleverMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Spend Time", 
        "key": "spendTimeCleverMenu"
    }, 
    "makeCriticismFlatMenu": {
        "image": "goal_mineFrustration-000000", 
        "name": "COMPLETED - Make Critical Statement", 
        "key": "makeCriticismFlatMenu"
    }, 
    "insecureSwarmYouMineConstruction": {
        "key": "insecureSwarmYouMineConstruction", 
        "constructionIdentifier": "insecureSwarmYouMine", 
        "name": "Insecurities", 
        "image": "tower_eyeTear-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Insecurities"
    }, 
    "trySomethingMenu": {
        "image": "goal_trophy-000000", 
        "name": "COMPLETED - Try Something New", 
        "key": "trySomethingMenu"
    }, 
    "complimentTower": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Compliment", 
        "key": "complimentTower", 
        "description": "Converts completeWork + generosity -> compliment"
    }, 
    "insecureMinePlaced": {
        "tower": "insecureMine", 
        "sourceTrait": "insecurity", 
        "key": "insecureMinePlaced"
    }, 
    "selfishnessMineButton": {
        "constructionKey": "selfishnessMineConstruction", 
        "name": "Selfishness", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_depositSin", 
        "currenciesMade": [
            "selfishness"
        ], 
        "entityKey": "selfishnessMine", 
        "limitingKeys": [
            "selfishnessMine", 
            "selfishnessMineConstruction"
        ], 
        "key": "selfishnessMineButton", 
        "description": "makes selfishness"
    }, 
    "sympathyAction": {
        "currenciesRequired": [
            "social_warm"
        ], 
        "towerKey": "sympathyTower", 
        "name": "Sympathy!", 
        "key": "sympathyAction"
    }, 
    "calmnessTowerPlaced": {
        "y": 23, 
        "x": 13, 
        "tower": "calmnessTower", 
        "key": "calmnessTowerPlaced"
    }, 
    "guiltMenu": {
        "image": "goal_eyeTear-000000", 
        "completeText": [
            "He sort of tries, but he never gets it. It just doesn't feel like he", 
            "knows how to feel."
        ], 
        "name": "COMPLETED - Guilt Partner", 
        "key": "guiltMenu"
    }, 
    "strong_ext": {
        "personHeld": "hurt", 
        "image": [
            "trait-33ff33", 
            "trait-2DE52D", 
            "trait-38FF38"
        ], 
        "name": "Strong", 
        "key": "strong_ext", 
        "sourceKey": "strong"
    }, 
    "takeOutFrustrationButton": {
        "constructionKey": "takeOutFrustrationGoalConstruction", 
        "name": "Take Out Frustrations", 
        "image": "goal_mineFrustration-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "takeOutFrustrationGoal", 
        "key": "takeOutFrustrationButton", 
        "description": "Requires frustration."
    }, 
    "tempTrait": {
        "image": "trait-ffffff", 
        "name": "temp", 
        "key": "tempTrait"
    }, 
    "calmPartnerButton": {
        "constructionKey": "calmPartnerGoalConstruction", 
        "name": "Calm Partner", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "calmPartnerGoal", 
        "key": "calmPartnerButton", 
        "description": "Requires support."
    }, 
    "rechargeTower": {
        "image": "tower_energy", 
        "activeImage": "tower_energy_activeOutline-0099ff", 
        "name": "Recharge", 
        "key": "rechargeTower", 
        "description": "Converts cheer -> will"
    }, 
    "strengthMineConstruction": {
        "key": "strengthMineConstruction", 
        "constructionIdentifier": "strengthMine", 
        "name": "Constructing - Strength", 
        "image": "trait-aaaaaa99_tower_weight", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Strength", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "oddityDeposit": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Oddities", 
        "key": "oddityDeposit", 
        "deposit": {
            "oddity": 3
        }
    }, 
    "toughTowerConstruction": {
        "key": "toughTowerConstruction", 
        "constructionIdentifier": "toughTower", 
        "name": "Constructing - Toughness", 
        "image": "trait-aaaaaa99_tower_energy", 
        "currencyRequested": {
            "strength": 3
        }, 
        "constructionName": "Toughness", 
        "killOnTransform": 0
    }, 
    "supportNeedTowerConstruction": {
        "key": "supportNeedTowerConstruction", 
        "constructionIdentifier": "supportNeedTower", 
        "name": "Constructing - Support", 
        "image": "trait-aaaaaa99_tower_heart", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Support", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "distract": {
        "name": "distraction", 
        "key": "distract", 
        "tags": [
            "distract"
        ]
    }, 
    "hisEmotionDeposit": {
        "randomPosition": 1, 
        "name": "His Emotion", 
        "image": "tower_trait-ffffff_sun", 
        "sourceTrait": "relationship", 
        "deposit": {
            "hisEmotion": 1
        }, 
        "key": "hisEmotionDeposit", 
        "interactionKeys": [
            "self"
        ], 
        "activeImage": "tower_trait-ffffff_sun_activeOutline-0099ff"
    }, 
    "socialMineConstruction": {
        "key": "socialMineConstruction", 
        "constructionIdentifier": "socialMine", 
        "name": "Constructing - Social", 
        "image": "trait-aaaaaa99_tower_mineSocial", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Social", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "towerFocusPathStopComponent": {
        "particleKey": "starParticleEffect"
    }, 
    "complimentMed": {
        "emotion": "joy", 
        "name": "compliment", 
        "image": "creepLarge-ffff00", 
        "memoryImage": "memoryJoy", 
        "health": 60, 
        "key": "complimentMed"
    }, 
    "defineRoleGoal": {
        "key": "defineRoleGoal", 
        "randomPosition": 0, 
        "name": "Define Roles", 
        "image": "goal_puzzle-000000", 
        "currencyRequested": {
            "social": 3
        }, 
        "entitiesToMake": "role", 
        "goalMenuKey": "defineRoleMenu", 
        "description": [
            "Really, just a few words and a couple actions and it becomes clear", 
            "who is what here."
        ]
    }, 
    "setRelation": {
        "flag": "relation", 
        "key": "setRelation"
    }, 
    "spendTimeCleverGoal": {
        "key": "spendTimeCleverGoal", 
        "randomPosition": 0, 
        "name": "Spend Time", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "goalMenuKey": "spendTimeCleverMenu"
    }, 
    "conversation": {
        "name": "Full Conversation", 
        "image": "trait-cc9900", 
        "personHeld": "relation", 
        "isaacEntities": [
            "pushInsecurityButton", 
            "talkInterestingButton", 
            "learnHimButton", 
            "calmPartnerButton"
        ], 
        "key": "conversation", 
        "interactionKeys": [
            "self", 
            "himself"
        ], 
        "maxLevel": 5
    }, 
    "connectHurtGoal": {
        "key": "connectHurtGoal", 
        "randomPosition": 0, 
        "name": "Connect To Your Hurt", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": [
            "insecurePathHurting", 
            "connectHurtDone"
        ], 
        "goalMenuKey": "connectHurtMenu"
    }, 
    "helpMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Help", 
        "key": "helpMenu"
    }, 
    "memory_criticismSwarmYou": {
        "image": "trait-013d70", 
        "memoryEmotions": [
            "sadness"
        ], 
        "key": "memory_criticismSwarmYou", 
        "name": "Criticism"
    }, 
    "makeComplimentSwarmGoal": {
        "key": "makeComplimentSwarmGoal", 
        "randomPosition": 0, 
        "name": "Make Swarm of Compliments", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "compliment": 3, 
            "social": 3
        }, 
        "entitiesToMake": "complimentSwarm", 
        "goalMenuKey": "makeComplimentSwarmMenu"
    }, 
    "truthAction": {
        "currenciesRequired": [
            "insecure"
        ], 
        "towerKey": "truthTower", 
        "currenciesToMake": [
            "truth"
        ], 
        "name": "The Truth!", 
        "key": "truthAction"
    }, 
    "memory_aloneFlatYou": {
        "image": "trait-013d70", 
        "memoryEmotions": [
            "sadness"
        ], 
        "key": "memory_aloneFlatYou", 
        "name": "Feeling Alone"
    }, 
    "reinforceComplimentGoal": {
        "key": "reinforceComplimentGoal", 
        "randomPosition": 1, 
        "name": "Reinforce Other's Compliment", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "compliment": 1
        }, 
        "entitiesToMake": "complimentSwarm", 
        "goalMenuKey": "reinforceComplimentMenu", 
        "timeToDeath": 30
    }, 
    "rechargeButton": {
        "constructionKey": "rechargeTowerConstruction", 
        "name": "Recharge", 
        "image": "tower_energy", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "rechargeTower", 
        "limitingKeys": [
            "rechargeTower", 
            "rechargeTowerConstruction"
        ], 
        "key": "rechargeButton", 
        "description": "Converts cheer -> will"
    }, 
    "relationshipMineButton": {
        "constructionKey": "relationshipMineConstruction", 
        "name": "Time Together", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_towerDate", 
        "currenciesMade": [
            "relationshipTime"
        ], 
        "entityKey": "relationshipMine", 
        "limitingKeys": [
            "relationshipMine", 
            "relationshipMineConstruction"
        ], 
        "key": "relationshipMineButton", 
        "description": "makes relationship time"
    }, 
    "insecurityPathWarm": {
        "startKey": "insecurity", 
        "endKey": "warm", 
        "key": "insecurityPathWarm"
    }, 
    "flirtationMineButton": {
        "aiVal": 5, 
        "constructionKey": "flirtationMineConstruction", 
        "name": "Flirtation", 
        "currenciesMade": [
            "flirtation"
        ], 
        "image": "tower_towerFlirt", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "flirtationMine", 
        "limitingKeys": [
            "flirtationMine", 
            "flirtationMineConstruction"
        ], 
        "key": "flirtationMineButton", 
        "interactionKeys": [
            "himself"
        ], 
        "description": "makes flirtation"
    }, 
    "flashback_sadness": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_sadness", 
        "emotionTags": "sadness", 
        "resourceKeys": [
            "sadness"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes sadness"
    }, 
    "flirtYouGoalConstruction": {
        "key": "flirtYouGoalConstruction", 
        "constructionIdentifier": "flirtYouGoal", 
        "name": "Constructing - Flirt", 
        "image": "trait-aaaaaa99_goal_heart-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Flirt", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "dreamDeathLarge": {
        "emotion": "sadness", 
        "name": "death of dream", 
        "image": "creepLarge-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 300, 
        "key": "dreamDeathLarge"
    }, 
    "memory_guiltFlatYou": {
        "image": "trait-013d70", 
        "memoryEmotions": [
            "sadness"
        ], 
        "key": "memory_guiltFlatYou", 
        "name": "Guilt"
    }, 
    "exploreStrengthGoal": {
        "key": "exploreStrengthGoal", 
        "randomPosition": 0, 
        "name": "Explore His Strength", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "support_you": 3
        }, 
        "entitiesToMake": "learnHistoryGoal", 
        "goalMenuKey": "exploreStrengthMenu"
    }, 
    "workWinMajor": {
        "resourceCount": 1, 
        "name": "Work Success", 
        "image": "tower_memoryRing", 
        "destination": "himself", 
        "key": "workWinMajor", 
        "emotionTags": [
            "joy"
        ], 
        "resourceKeys": "workWinLarge", 
        "activeImage": "tower_memoryRing_activeOutline-0099ff"
    }, 
    "workWin": {
        "name": "dream completion", 
        "key": "workWin", 
        "tags": [
            "workWin"
        ]
    }, 
    "takeConnectGoal": {
        "key": "takeConnectGoal", 
        "randomPosition": 0, 
        "name": "Take Friend's Connection", 
        "image": "goal_goalMeetNewPerson-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": [
            "cleverPathRelationship", 
            "warmPathRelationship", 
            "takeConnectDone"
        ], 
        "goalMenuKey": "takeConnectMenu"
    }, 
    "acceptMeanlessGoalConstruction": {
        "key": "acceptMeanlessGoalConstruction", 
        "constructionIdentifier": "acceptMeanlessGoal", 
        "name": "Constructing - Accept Meaninglessness", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Accept Meaninglessness", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "askForBeliefGoalConstruction": {
        "key": "askForBeliefGoalConstruction", 
        "constructionIdentifier": "askForBeliefGoal", 
        "name": "Constructing - Ask For Belief", 
        "image": "trait-aaaaaa99_goal_trophy-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Ask For Belief", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "dreamDeath": {
        "name": "death of a dream", 
        "key": "dreamDeath", 
        "tags": [
            "dreamDeath"
        ]
    }, 
    "askForBeliefButton": {
        "constructionKey": "askForBeliefGoalConstruction", 
        "name": "Ask For Belief", 
        "image": "goal_trophy-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "askForBeliefGoal", 
        "key": "askForBeliefButton", 
        "description": "Requires will."
    }, 
    "memory_complimentFlatYou": {
        "image": "trait-e6e617", 
        "memoryEmotions": [
            "joy"
        ], 
        "key": "memory_complimentFlatYou", 
        "name": "Compliment"
    }, 
    "hurting_ext": {
        "personHeld": "hurt", 
        "image": [
            "trait-660066", 
            "trait-5B005B", 
            "trait-700070"
        ], 
        "name": "Hurting", 
        "key": "hurting_ext", 
        "sourceKey": "hurting"
    }, 
    "choreMaker": {
        "dayCount": 5, 
        "name": "Chore Maker", 
        "key": "choreMaker", 
        "dayStartEntity": "chore"
    }, 
    "loosenUpMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Loosen Up", 
        "key": "loosenUpMenu"
    }, 
    "solveProbeAction": {
        "currenciesRequired": [
            "probedProblem"
        ], 
        "towerKey": "solveProbeTower", 
        "currenciesToMake": [
            "activity"
        ], 
        "name": "Solve Problem", 
        "key": "solveProbeAction"
    }, 
    "swarm": {
        "name": "swarm", 
        "key": "swarm", 
        "tags": [
            "swarm"
        ]
    }, 
    "memory_resentYou": {
        "image": "trait-aa1717", 
        "memoryEmotions": [
            "anger"
        ], 
        "key": "memory_resentYou", 
        "name": "Resent Your Failures"
    }, 
    "viceFlatYou": {
        "emotionsToAdd": {
            "viceMed": 1
        }, 
        "name": "Vice", 
        "image": "tower_memoryRing", 
        "key": "viceFlatYou", 
        "memoryKey": "memory_viceFlatYou", 
        "emotionTags": [
            "joy", 
            "self"
        ], 
        "resourceKey": "viceFlatYouMineConstruction", 
        "activeImage": "tower_memoryRing_activeOutline-0099ff"
    }, 
    "deriveWorkTopicGoal": {
        "key": "deriveWorkTopicGoal", 
        "randomPosition": 0, 
        "name": "Derive Work Points", 
        "image": "goal_towerThinkAbout-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": "workTopicDeposit", 
        "goalMenuKey": "deriveWorkTopicMenu"
    }, 
    "makeComplimentSwarmButton": {
        "constructionKey": "makeComplimentSwarmGoalConstruction", 
        "name": "Make Swarm of Compliments", 
        "image": "goal_mineCheer-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeComplimentSwarmGoal", 
        "key": "makeComplimentSwarmButton", 
        "description": "Requires social, compliment."
    }, 
    "reinforceOldFailGoal": {
        "key": "reinforceOldFailGoal", 
        "randomPosition": 1, 
        "name": "Reinforce Old Failures", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "oldFail": 1
        }, 
        "entitiesToMake": "oldFailSwarm", 
        "goalMenuKey": "reinforceOldFailMenu", 
        "timeToDeath": 30
    }, 
    "socialWarmMineButton": {
        "constructionKey": "socialWarmMineConstruction", 
        "name": "Social", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_mineSocial", 
        "currenciesMade": [
            "social_warm"
        ], 
        "entityKey": "socialWarmMine", 
        "limitingKeys": [
            "socialWarmMine", 
            "socialWarmMineConstruction"
        ], 
        "key": "socialWarmMineButton", 
        "description": "makes social"
    }, 
    "becomeCriticalGoalConstruction": {
        "key": "becomeCriticalGoalConstruction", 
        "constructionIdentifier": "becomeCriticalGoal", 
        "name": "Constructing - Become Critical", 
        "image": "trait-aaaaaa99_goal_mineFrustration-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Become Critical", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "swarmTower": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Swarm", 
        "key": "swarmTower", 
        "description": "Converts social -> swarm"
    }, 
    "workWinSmall": {
        "emotion": "joy", 
        "name": "work success", 
        "image": "creepLarge-ffff00", 
        "memoryImage": "memoryJoy", 
        "health": 60, 
        "key": "workWinSmall"
    }, 
    "defineRoleGoalConstruction": {
        "key": "defineRoleGoalConstruction", 
        "constructionIdentifier": "defineRoleGoal", 
        "name": "Constructing - Define Roles", 
        "image": "trait-aaaaaa99_goal_puzzle-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Define Roles", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "relationship": {
        "sector": [
            2, 
            3
        ], 
        "name": "Relationship", 
        "aliveEntities": {
            "niceGoal": 5
        }, 
        "image": "trait-ffcc00", 
        "personHeld": "relation", 
        "isaacEntities": [
            "socialMineButton", 
            "defineRoleBranch", 
            "quietTimeButton", 
            "socialButton", 
            "startConverseButton"
        ], 
        "key": "relationship", 
        "interactionKeys": [
            "self", 
            "himself"
        ], 
        "description": "What is this going to be?"
    }, 
    "flirtHimMenu": {
        "image": "goal_heart-000000", 
        "name": "COMPLETED - Flirt", 
        "key": "flirtHimMenu"
    }, 
    "giveInGoal": {
        "key": "giveInGoal", 
        "randomPosition": 0, 
        "name": "Give In To Hurt", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "pain": 3
        }, 
        "entitiesToMake": "allowWeaknessGoal", 
        "goalMenuKey": "giveInMenu"
    }, 
    "makeStupidityFlatGoal": {
        "key": "makeStupidityFlatGoal", 
        "randomPosition": 0, 
        "name": "Make Statement About Stupidity", 
        "image": "goal_mineFrustration-000000", 
        "currencyRequested": {
            "state": 3, 
            "stupid": 3
        }, 
        "entitiesToMake": "stupidFlat", 
        "goalMenuKey": "makeStupidityFlatMenu"
    }, 
    "hisBadWork_ext": {
        "personHeld": "him", 
        "image": [
            "trait-3333ff", 
            "trait-2D2DE5", 
            "trait-3838FF"
        ], 
        "name": "His Bad Work", 
        "key": "hisBadWork_ext", 
        "sourceKey": "hisBadWork"
    }, 
    "deriveWorkTopicMenu": {
        "image": "goal_towerThinkAbout-000000", 
        "name": "COMPLETED - Derive Work Points", 
        "key": "deriveWorkTopicMenu"
    }, 
    "openUpMenu": {
        "image": "goal_goalConvinceWife-000000", 
        "name": "COMPLETED - Open Up", 
        "key": "openUpMenu"
    }, 
    "stupidityMed": {
        "emotion": "anger", 
        "name": "stupidity", 
        "image": "creepLarge-ff0000", 
        "memoryImage": "memoryAnger", 
        "health": 60, 
        "key": "stupidityMed"
    }, 
    "workWinDeposit": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Dream Completion", 
        "key": "workWinDeposit", 
        "deposit": {
            "workWin": 3
        }
    }, 
    "flashback_criticismSmall": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_criticismSmall", 
        "emotionTags": "criticismSmall", 
        "resourceKeys": [
            "criticismSmall"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes criticismSmall"
    }, 
    "complimentYouGoal": {
        "key": "complimentYouGoal", 
        "randomPosition": 0, 
        "name": "Compliment You", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "cheer": 3
        }, 
        "entitiesToMake": "complimentSwarmYou", 
        "goalMenuKey": "complimentYouMenu"
    }, 
    "anxiety": {
        "name": "anxiety", 
        "key": "anxiety", 
        "tags": [
            "anxiety"
        ]
    }, 
    "thankMenu": {
        "image": "goal_heart-000000", 
        "name": "COMPLETED - Thank For Usefulness", 
        "key": "thankMenu"
    }, 
    "youRelationButtonBranch": {
        "flagToCheck": "youRelation", 
        "key": "youRelationButtonBranch", 
        "notFlagEntities": "startRelationYouButton"
    }, 
    "shareJoyAction": {
        "currenciesRequired": [
            "social"
        ], 
        "towerKey": "shareJoyTower", 
        "name": "Share Joy", 
        "key": "shareJoyAction"
    }, 
    "askAboutRestlessGoal": {
        "key": "askAboutRestlessGoal", 
        "randomPosition": 0, 
        "name": "Ask About Restlessness", 
        "image": "goal_goalAskAbout-000000", 
        "currencyRequested": {
            "social": 3
        }, 
        "entitiesToMake": "partnerInfoDeposit", 
        "goalMenuKey": "askAboutRestlessMenu"
    }, 
    "funPathYou": {
        "startKey": "fun", 
        "endKey": "you", 
        "key": "funPathYou"
    }, 
    "switchHelpGoal": {
        "entitiesToMake": "helpGoal", 
        "key": "switchHelpGoal"
    }, 
    "project": {
        "playerKillable": "true"
    }, 
    "swarmButton": {
        "constructionKey": "swarmTowerConstruction", 
        "name": "Swarm", 
        "image": "tower_newNote", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "swarmTower", 
        "limitingKeys": [
            "swarmTower", 
            "swarmTowerConstruction"
        ], 
        "key": "swarmButton", 
        "subPanel": "Towers", 
        "description": "Converts social -> swarm"
    }, 
    "breakdownMenu": {
        "endGame": 1, 
        "completeText": [
            "This is just too much for you. You just cannot handle this amount of", 
            "constant emotion."
        ], 
        "key": "breakdownMenu"
    }, 
    "disableHim": {
        "timeToDeath": 3000, 
        "name": "He's just trying to process this", 
        "key": "disableHim", 
        "traitsToDisable": [
            "him", 
            "restless", 
            "hisWork", 
            "hisGoodWork", 
            "hisBadWork"
        ]
    }, 
    "sadAttack": {
        "emotionsToAdd": {
            "sadness": 1
        }, 
        "name": "Sadness Burst", 
        "image": "tower_pain", 
        "key": "sadAttack", 
        "memoryKey": "memory_sadAttack", 
        "emotionTags": "self", 
        "resourceKey": "sadAttackMineConstruction", 
        "activeImage": "tower_pain_activeOutline-0099ff"
    }, 
    "takeSupportTowerConstruction": {
        "key": "takeSupportTowerConstruction", 
        "constructionIdentifier": "takeSupportTower", 
        "name": "Constructing - Take Support", 
        "image": "trait-aaaaaa99_tower_dependence", 
        "currencyRequested": {
            "support": 5
        }, 
        "constructionName": "Take Support", 
        "killOnTransform": 0
    }, 
    "becomeCriticalMenu": {
        "image": "goal_mineFrustration-000000", 
        "name": "COMPLETED - Become Critical", 
        "key": "becomeCriticalMenu"
    }, 
    "rechargeTowerConstruction": {
        "key": "rechargeTowerConstruction", 
        "constructionIdentifier": "rechargeTower", 
        "name": "Constructing - Recharge", 
        "image": "trait-aaaaaa99_tower_energy", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Recharge", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "whatsNewMaker": {
        "dayCount": 5, 
        "name": "New Maker", 
        "key": "whatsNewMaker", 
        "dayStartEntity": "whatsNewGoal"
    }, 
    "gainControl_sadness": {
        "barColor": "9999cc", 
        "text": "You need some time to push through this sadness", 
        "textColor": 66, 
        "key": "gainControl_sadness"
    }, 
    "killFaithCrisis": {
        "entitiesToKill": [
            "faithCrisis"
        ], 
        "key": "killFaithCrisis"
    }, 
    "insecurityToCruelty": {
        "sourceTrait": "insecurity", 
        "newTrait": "cruelty", 
        "key": "insecurityToCruelty"
    }, 
    "makeAllPathMaker": {
        "csv": "pathMaker", 
        "key": "makeAllPathMaker"
    }, 
    "warmPathYou": {
        "startKey": "warm", 
        "endKey": "you", 
        "key": "warmPathYou"
    }, 
    "workWinLarge": {
        "emotion": "joy", 
        "name": "work success", 
        "image": "creepLarge-ffff00", 
        "memoryImage": "memoryJoy", 
        "health": 300, 
        "key": "workWinLarge"
    }, 
    "diveHurtGoalConstruction": {
        "key": "diveHurtGoalConstruction", 
        "constructionIdentifier": "diveHurtGoal", 
        "name": "Constructing - Submerge In Hurt", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Submerge In Hurt", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "supportNeedButton": {
        "constructionKey": "supportNeedTowerConstruction", 
        "name": "Support", 
        "image": "tower_heart", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "supportNeedTower", 
        "limitingKeys": [
            "supportNeedTower", 
            "supportNeedTowerConstruction"
        ], 
        "key": "supportNeedButton", 
        "subPanel": "Towers", 
        "description": "Converts need -> support"
    }, 
    "fadingMemory": {
        "mapSpawnKey": "memoryExtension", 
        "playerKillable": "true", 
        "timeToDeath": 300
    }, 
    "selfValueAction": {
        "currenciesRequired": [
            "value"
        ], 
        "towerKey": "selfValueTower", 
        "name": "Value", 
        "key": "selfValueAction"
    }, 
    "aloneFlatYou": {
        "emotionsToAdd": {
            "aloneMed": 1
        }, 
        "name": "Feeling Alone", 
        "image": "tower_eyeTear", 
        "key": "aloneFlatYou", 
        "memoryKey": "memory_aloneFlatYou", 
        "emotionTags": [
            "sadness", 
            "self"
        ], 
        "resourceKey": "aloneFlatYouMineConstruction", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "crueltyAction": {
        "currenciesRequired": [
            "frustration"
        ], 
        "towerKey": "crueltyTower", 
        "currenciesToMake": [
            "cruelty"
        ], 
        "name": "Be Cruel", 
        "key": "crueltyAction"
    }, 
    "planSomethingFunGoal": {
        "key": "planSomethingFunGoal", 
        "randomPosition": 1, 
        "name": "Plan Something Fun", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "cheer": 3
        }, 
        "entitiesToMake": "doFunGoal", 
        "goalMenuKey": "planSomethingFunMenu"
    }, 
    "anger": {
        "emotion": "anger", 
        "name": "anger", 
        "image": "creep-ff0000", 
        "memoryImage": "memoryAnger", 
        "health": 10, 
        "key": "anger"
    }, 
    "himSupportAction": {
        "currenciesRequired": [
            "strength"
        ], 
        "towerKey": "himSupportTower", 
        "currenciesToMake": [
            "support"
        ], 
        "name": "Support", 
        "key": "himSupportAction"
    }, 
    "interestingDeposit": {
        "timeToDeath": 300, 
        "image": "tower_newNote", 
        "deposit": {
            "interesting": 3
        }, 
        "key": "interestingDeposit", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Interesting Things"
    }, 
    "capable_ext": {
        "personHeld": "him", 
        "image": [
            "trait-ccffcc", 
            "trait-B7E5B7", 
            "trait-E0FFE0"
        ], 
        "name": "His Capability", 
        "key": "capable_ext", 
        "sourceKey": "capable"
    }, 
    "winMenu": {
        "endGame": 1, 
        "completeText": "What did you think would happen?", 
        "name": "COMPLETED - Win Game!", 
        "key": "winMenu", 
        "image": "goal_trophy-000000"
    }, 
    "makeOldFailFlatButton": {
        "constructionKey": "makeOldFailFlatGoalConstruction", 
        "name": "Make Statement of Old Failures", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeOldFailFlatGoal", 
        "key": "makeOldFailFlatButton", 
        "description": "Requires state, old failures."
    }, 
    "selfDistractionAction": {
        "currenciesRequired": [
            "anxiety"
        ], 
        "towerKey": "selfDistractionTower", 
        "currenciesToMake": [
            "will"
        ], 
        "name": "Distraction!", 
        "key": "selfDistractionAction"
    }, 
    "overcomeHurtGoal": {
        "key": "overcomeHurtGoal", 
        "randomPosition": 0, 
        "name": "Overcome Hurt", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "calm": 3
        }, 
        "entitiesToMake": "flipHurt", 
        "goalMenuKey": "overcomeHurtMenu"
    }, 
    "strength": {
        "name": "strength", 
        "key": "strength", 
        "tags": [
            "strength"
        ]
    }, 
    "makeDreamDeathMajorButton": {
        "constructionKey": "makeDreamDeathMajorGoalConstruction", 
        "name": "Talk About Death of Dream", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeDreamDeathMajorGoal", 
        "key": "makeDreamDeathMajorButton", 
        "description": "Requires major, death of a dream."
    }, 
    "gainControl_joy": {
        "barColor": "cccc99", 
        "text": "It's hard to control yourself when you're this happy", 
        "textColor": 666622, 
        "key": "gainControl_joy"
    }, 
    "self": {
        "name": "Self", 
        "image": "trait-eeeeee_self", 
        "health": 200, 
        "key": "self", 
        "focusCount": 5, 
        "y": 0, 
        "x": 0
    }, 
    "triggerCrisisGoal": {
        "key": "triggerCrisisGoal", 
        "randomPosition": 0, 
        "name": "Trigger Crisis", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "cruelty": 3
        }, 
        "entitiesToMake": "hisBadWorkToFaithCrisis", 
        "goalMenuKey": "triggerCrisisMenu"
    }, 
    "restLife_ext": {
        "personHeld": "you", 
        "image": [
            "trait-66cc66", 
            "trait-5BB75B", 
            "trait-70E070"
        ], 
        "name": "Rest of Your Life", 
        "key": "restLife_ext", 
        "sourceKey": "restLife"
    }, 
    "takeConnectDone": {
        "buttonKey": "takeConnectButton", 
        "flag": "takeConnectDone", 
        "key": "takeConnectDone"
    }, 
    "workTopic": {
        "name": "work topic", 
        "key": "workTopic", 
        "tags": [
            "workTopic"
        ]
    }, 
    "triggerCrisisButton": {
        "constructionKey": "triggerCrisisGoalConstruction", 
        "name": "Trigger Crisis", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "triggerCrisisGoal", 
        "key": "triggerCrisisButton", 
        "interactionKeys": [
            "self"
        ], 
        "description": "Requires cruelty."
    }, 
    "social_warm": {
        "name": "social", 
        "key": "social_warm", 
        "tags": [
            "social_warm"
        ]
    }, 
    "worthlessPathNewRelationship": {
        "startKey": "worthless", 
        "endKey": "newRelationship", 
        "key": "worthlessPathNewRelationship"
    }, 
    "becomeCriticalGoal": {
        "key": "becomeCriticalGoal", 
        "randomPosition": 0, 
        "name": "Become Critical", 
        "image": "goal_mineFrustration-000000", 
        "currencyRequested": {
            "cruelty": 3
        }, 
        "entitiesToMake": "insecurityToCruelty", 
        "goalMenuKey": "becomeCriticalMenu", 
        "description": "It takes cruelty to be cruel."
    }, 
    "newRelationshipToRelationship": {
        "sourceTrait": "newRelationship", 
        "newTrait": "relationship", 
        "key": "newRelationshipToRelationship"
    }, 
    "criticismTowerConstruction": {
        "key": "criticismTowerConstruction", 
        "constructionIdentifier": "criticismTower", 
        "name": "Constructing - Criticize", 
        "image": "trait-aaaaaa99_tower_mineFrustration", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Criticize", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "worthlessFeelMineConstruction": {
        "key": "worthlessFeelMineConstruction", 
        "constructionIdentifier": "worthlessFeelMine", 
        "name": "Feel Worthless", 
        "image": "tower_eyeTear-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Feel Worthless"
    }, 
    "makeSlowWorkSwarmButton": {
        "constructionKey": "makeSlowWorkSwarmGoalConstruction", 
        "name": "Make Swarm About Slow Work", 
        "image": "goal_mineFrustration-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeSlowWorkSwarmGoal", 
        "key": "makeSlowWorkSwarmButton", 
        "description": "Requires swarm, slow work."
    }, 
    "himSupportTowerConstruction": {
        "key": "himSupportTowerConstruction", 
        "constructionIdentifier": "himSupportTower", 
        "name": "Constructing - Support", 
        "image": "trait-aaaaaa99_tower_dependence", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Support", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "askHelpGoalConstruction": {
        "key": "askHelpGoalConstruction", 
        "constructionIdentifier": "askHelpGoal", 
        "name": "Constructing - Ask For Help", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Ask For Help", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "hardWorkGoalConstruction": {
        "key": "hardWorkGoalConstruction", 
        "constructionIdentifier": "hardWorkGoal", 
        "name": "Constructing - Hard Work", 
        "image": "trait-aaaaaa99_goal_weight-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Hard Work", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "searchWorthMenu": {
        "image": "goal_memoryLearn-000000", 
        "name": "COMPLETED - Why Are You Like This?", 
        "key": "searchWorthMenu"
    }, 
    "needHelpButton": {
        "constructionKey": "needHelpGoalConstruction", 
        "name": "Need Help Yourself", 
        "image": "goal_minePain-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "needHelpGoal", 
        "key": "needHelpButton", 
        "description": "Requires need."
    }, 
    "pain": {
        "name": "pain", 
        "key": "pain", 
        "tags": [
            "pain"
        ]
    }, 
    "findHelpGoal": {
        "key": "findHelpGoal", 
        "randomPosition": 0, 
        "name": "Find Way To Be Helpful", 
        "image": "goal_heart-000000", 
        "currencyRequested": {
            "partnerInfo": 3
        }, 
        "entitiesToMake": "findHelpResult", 
        "goalMenuKey": "findHelpMenu", 
        "description": "Surely, there's no one better suited to help than you."
    }, 
    "choreMenu": {
        "image": "goal_goalPayRent-000000", 
        "name": "COMPLETED - Chores", 
        "key": "choreMenu"
    }, 
    "complimentFlatYouMineConstruction": {
        "key": "complimentFlatYouMineConstruction", 
        "constructionIdentifier": "complimentFlatYouMine", 
        "name": "Compliment", 
        "image": "tower_memoryRing-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Compliment"
    }, 
    "hardWorkButton": {
        "aiVal": 3, 
        "constructionKey": "hardWorkGoalConstruction", 
        "name": "Hard Work", 
        "image": "goal_weight-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "hardWorkGoal", 
        "key": "hardWorkButton", 
        "interactionKeys": [
            "himself"
        ], 
        "description": [
            "Requires will.", 
            "Makes goodWork."
        ]
    }, 
    "connectHurtMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Connect To Your Hurt", 
        "key": "connectHurtMenu"
    }, 
    "newParticle": {
        "effectRadius": 25, 
        "image": "dot-ffd700", 
        "key": "newParticle"
    }, 
    "accuseSelfishButton": {
        "constructionKey": "accuseSelfishGoalConstruction", 
        "name": "Accuse of Selfishness", 
        "image": "goal_goalAskAbout-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "accuseSelfishGoal", 
        "key": "accuseSelfishButton", 
        "description": "Requires social, cruelty."
    }, 
    "findHelpGoalConstruction": {
        "key": "findHelpGoalConstruction", 
        "constructionIdentifier": "findHelpGoal", 
        "name": "Constructing - Find Way To Be Helpful", 
        "image": "trait-aaaaaa99_goal_heart-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Find Way To Be Helpful", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "acceptMeanlessGoal": {
        "key": "acceptMeanlessGoal", 
        "randomPosition": 0, 
        "name": "Accept Meaninglessness", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "insecure": 1
        }, 
        "entitiesToMake": "worthlessFeel", 
        "goalMenuKey": "acceptMeanlessMenu"
    }, 
    "stupidityFlat": {
        "resourceCount": 1, 
        "name": "Stupidity", 
        "image": "tower_memoryDefineSelf", 
        "destination": "himself", 
        "key": "stupidityFlat", 
        "emotionTags": [
            "anger"
        ], 
        "resourceKeys": "stupidityMed", 
        "activeImage": "tower_memoryDefineSelf_activeOutline-0099ff"
    }, 
    "himRelationButtonBranch": {
        "flagToCheck": "himRelation", 
        "key": "himRelationButtonBranch", 
        "notFlagEntities": "startRelationHimButton"
    }, 
    "beBelievedInMenu": {
        "image": "goal_trophy-000000", 
        "name": "COMPLETED - Be Believed In", 
        "key": "beBelievedInMenu"
    }, 
    "flirtYouButton": {
        "constructionKey": "flirtYouGoalConstruction", 
        "name": "Flirt", 
        "image": "goal_heart-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "flirtYouGoal", 
        "key": "flirtYouButton", 
        "interactionKeys": [
            "self"
        ], 
        "description": [
            "Requires flirtation.", 
            "Makes Info on Partner."
        ]
    }, 
    "criticismMed": {
        "emotion": "sadness", 
        "name": "criticism", 
        "image": "creepLarge-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 60, 
        "key": "criticismMed"
    }, 
    "restless_ext": {
        "personHeld": "him", 
        "image": [
            "trait-ff66ff", 
            "trait-E55BE5", 
            "trait-FF70FF"
        ], 
        "name": "His Restlessness", 
        "key": "restless_ext", 
        "sourceKey": "restless"
    }, 
    "selfPathYou": {
        "startKey": "self", 
        "endKey": "you", 
        "key": "selfPathYou"
    }, 
    "talkAboutHimGoal": {
        "key": "talkAboutHimGoal", 
        "randomPosition": 0, 
        "name": "Talk About Him", 
        "image": "goal_newNote-000000", 
        "currencyRequested": {
            "partnerInfo": 3, 
            "social": 3
        }, 
        "entitiesToMake": "oldFailMed", 
        "goalMenuKey": "talkAboutHimMenu"
    }, 
    "relationshipPathStrong": {
        "startKey": "relationship", 
        "endKey": "strong", 
        "key": "relationshipPathStrong"
    }, 
    "fishComplimentsButton": {
        "constructionKey": "fishComplimentsGoalConstruction", 
        "name": "Fish For Compliments", 
        "image": "goal_mineCheer-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "fishComplimentsGoal", 
        "key": "fishComplimentsButton", 
        "description": [
            "Requires insecurity.", 
            "Makes value."
        ]
    }, 
    "newRelationship": {
        "sector": [
            2, 
            3
        ], 
        "name": "New Relationship", 
        "image": "trait-ff0000", 
        "personHeld": "relation", 
        "isaacEntities": [
            "flirtYouButton", 
            "flirtHimButton", 
            "tryForConnectionYouButton", 
            "tryForConnectionHimButton", 
            "flirtButton", 
            "flirtationMineButton"
        ], 
        "key": "newRelationship", 
        "interactionKeys": [
            "self", 
            "himself"
        ], 
        "maxLevel": 10, 
        "description": "New relationship. New you?"
    }, 
    "social_clever": {
        "name": "social", 
        "key": "social_clever", 
        "tags": [
            "social_clever"
        ]
    }, 
    "busyWorkDeposit": {
        "randomPosition": 1, 
        "timeToDeath": 120, 
        "image": "tower_towerThinkAbout", 
        "sourceTrait": "hisWork", 
        "deposit": {
            "busyWork": 3
        }, 
        "key": "busyWorkDeposit", 
        "activeImage": "tower_towerThinkAbout_activeOutline-0099ff", 
        "name": "Busy Work"
    }, 
    "rejectMeanlessButton": {
        "constructionKey": "rejectMeanlessGoalConstruction", 
        "name": "Reject Meaninglessness", 
        "image": "goal_openMind-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "rejectMeanlessGoal", 
        "key": "rejectMeanlessButton", 
        "description": "Requires value."
    }, 
    "startPaths": {
        "entitiesToMake": [
            "selfPathYou", 
            "himPathHimself"
        ], 
        "key": "startPaths"
    }, 
    "warm_ext": {
        "personHeld": "friend", 
        "image": [
            "trait-ed9933", 
            "trait-D5892D", 
            "trait-FFA838"
        ], 
        "name": "Warm Friend", 
        "key": "warm_ext", 
        "sourceKey": "warm"
    }, 
    "askAboutRestlessMenu": {
        "image": "goal_goalAskAbout-000000", 
        "name": "COMPLETED - Ask About Restlessness", 
        "key": "askAboutRestlessMenu"
    }, 
    "applyAction": {
        "currenciesRequired": [
            "frustration"
        ], 
        "towerKey": "applyTower", 
        "currenciesToMake": [
            "will"
        ], 
        "name": "Apply", 
        "key": "applyAction"
    }, 
    "searchWorthGoal": {
        "key": "searchWorthGoal", 
        "randomPosition": 0, 
        "name": "Why Are You Like This?", 
        "image": "goal_memoryLearn-000000", 
        "currencyRequested": {
            "insecure": 3
        }, 
        "entitiesToMake": "insecurityToSearchingWorth", 
        "goalMenuKey": "searchWorthMenu"
    }, 
    "toughTower": {
        "description": "Uses strength to calm anger, joy, sadness", 
        "charges": 3, 
        "image": "tower_energy", 
        "damage": 60, 
        "damageMultipliers": {
            "anger": 1, 
            "joy": 1, 
            "sadness": 1
        }, 
        "impulseTicks": 3, 
        "key": "toughTower", 
        "activeImage": "tower_energy_activeOutline-0099ff", 
        "name": "Toughness"
    }, 
    "reinforceOldFailMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Reinforce Old Failures", 
        "key": "reinforceOldFailMenu"
    }, 
    "giveInMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Give In To Hurt", 
        "key": "giveInMenu"
    }, 
    "searchingWorth_ext": {
        "personHeld": "you", 
        "image": [
            "trait-00aa00", 
            "trait-009900", 
            "trait-00BB00"
        ], 
        "name": "Searching For Worth", 
        "key": "searchingWorth_ext", 
        "sourceKey": "searchingWorth"
    }, 
    "flirtHimGoalConstruction": {
        "key": "flirtHimGoalConstruction", 
        "constructionIdentifier": "flirtHimGoal", 
        "name": "Constructing - Flirt", 
        "image": "trait-aaaaaa99_goal_heart-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Flirt", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "makeOldFailSwarmButton": {
        "constructionKey": "makeOldFailSwarmGoalConstruction", 
        "name": "Make Swarm About Old Failures", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeOldFailSwarmGoal", 
        "key": "makeOldFailSwarmButton", 
        "description": "Requires swarm, old failures."
    }, 
    "socialCleverMineConstruction": {
        "key": "socialCleverMineConstruction", 
        "constructionIdentifier": "socialCleverMine", 
        "name": "Constructing - Social", 
        "image": "trait-aaaaaa99_tower_mineSocial", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Social", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "talkInterestingGoalConstruction": {
        "key": "talkInterestingGoalConstruction", 
        "constructionIdentifier": "talkInterestingGoal", 
        "name": "Constructing - Talk of Interesting Things", 
        "image": "trait-aaaaaa99_goal_goalAskOut-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Talk of Interesting Things", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "forceOpennessGoalConstruction": {
        "key": "forceOpennessGoalConstruction", 
        "constructionIdentifier": "forceOpennessGoal", 
        "name": "Constructing - Force Some Openness", 
        "image": "trait-aaaaaa99_goal_weight-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Force Some Openness", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "complimentFlat": {
        "resourceCount": 1, 
        "name": "Compliment", 
        "image": "tower_memoryRing", 
        "destination": "himself", 
        "key": "complimentFlat", 
        "emotionTags": [
            "joy"
        ], 
        "resourceKeys": "complimentMed", 
        "activeImage": "tower_memoryRing_activeOutline-0099ff"
    }, 
    "generousTower": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Be Generous", 
        "key": "generousTower", 
        "description": "Converts cheer -> generosity"
    }, 
    "findLifeHelpMenu": {
        "image": "goal_insecure-000000", 
        "name": "COMPLETED - Find Way To Help From Your Life", 
        "key": "findLifeHelpMenu"
    }, 
    "toast": {
        "timeToDeath": 30, 
        "key": "toast"
    }, 
    "majorTowerConstruction": {
        "key": "majorTowerConstruction", 
        "constructionIdentifier": "majorTower", 
        "name": "Constructing - Major Statement", 
        "image": "trait-aaaaaa99_tower_newNote", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Major Statement", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "singleHealthComponent": {
        "health": 1
    }, 
    "socialCleverMineButton": {
        "constructionKey": "socialCleverMineConstruction", 
        "name": "Social", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_mineSocial", 
        "currenciesMade": [
            "social_clever"
        ], 
        "entityKey": "socialCleverMine", 
        "limitingKeys": [
            "socialCleverMine", 
            "socialCleverMineConstruction"
        ], 
        "key": "socialCleverMineButton", 
        "description": "makes social"
    }, 
    "whatsNewGoal": {
        "key": "whatsNewGoal", 
        "randomPosition": 1, 
        "name": "What Have You Tried?", 
        "makeOnTimeOut": "guiltFlatYou", 
        "image": "goal_spark-000000", 
        "sourceTrait": "you", 
        "currencyRequested": {
            "newThing": 3
        }, 
        "goalMenuKey": "whatsNewMenu", 
        "interactionKeys": [
            "self"
        ], 
        "timeToDeath": 150
    }, 
    "convinceActivityMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Convince To Try Activity", 
        "key": "convinceActivityMenu"
    }, 
    "worthlessFeelMine": {
        "resourceCount": 1, 
        "name": "Feel Worthless", 
        "image": "tower_eyeTear", 
        "key": "worthlessFeelMine", 
        "emotionTags": [
            "sadness", 
            "self", 
            "worthlessMed"
        ], 
        "resourceKeys": [
            "worthlessMed"
        ], 
        "activeImage": "tower_eyeTear_activeOutline-0099ff", 
        "description": "makes worthlessMed"
    }, 
    "beSupportedDone": {
        "buttonKey": "beSupportedButton", 
        "flag": "beSupportedDone", 
        "key": "beSupportedDone"
    }, 
    "relationshipTime": {
        "name": "relationship time", 
        "key": "relationshipTime", 
        "tags": [
            "relationshipTime"
        ]
    }, 
    "flirtTower": {
        "image": "tower_towerFlirt", 
        "activeImage": "tower_towerFlirt_activeOutline-0099ff", 
        "name": "Flirtation", 
        "key": "flirtTower", 
        "description": [
            "It's just hard for you", 
            "Converts openness -> flirtation"
        ]
    }, 
    "socialCleverMine": {
        "image": "tower_mineSocial", 
        "resourceKeys": [
            "social_clever"
        ], 
        "name": "Social", 
        "key": "socialCleverMine", 
        "activeImage": "tower_mineSocial_activeOutline-0099ff"
    }, 
    "personHealAction": {
        "health": 0
    }, 
    "reinforceCriticismGoal": {
        "key": "reinforceCriticismGoal", 
        "randomPosition": 1, 
        "name": "Reinforce Other's Criticism", 
        "image": "goal_mineFrustration-000000", 
        "currencyRequested": {
            "criticism": 1
        }, 
        "entitiesToMake": "criticismSwarm", 
        "goalMenuKey": "reinforceCriticismMenu", 
        "timeToDeath": 30
    }, 
    "tiredSwarmHim": {
        "resourceCount": 3, 
        "name": "Fatigue", 
        "image": "tower_numb", 
        "destination": "himself", 
        "key": "tiredSwarmHim", 
        "emotionTags": [
            "sadness"
        ], 
        "resourceKeys": "tiredSmall", 
        "activeImage": "tower_numb_activeOutline-0099ff"
    }, 
    "damageIndicator": {
        "timeToDeath": 5
    }, 
    "makeCriticismFlatGoalConstruction": {
        "key": "makeCriticismFlatGoalConstruction", 
        "constructionIdentifier": "makeCriticismFlatGoal", 
        "name": "Constructing - Make Critical Statement", 
        "image": "trait-aaaaaa99_goal_mineFrustration-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Make Critical Statement", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "reachOutMenu": {
        "image": "goal_goalMeetNewPerson-000000", 
        "name": "COMPLETED - Reach Out To Someone", 
        "key": "reachOutMenu"
    }, 
    "acceptConnectionYouGoal": {
        "key": "acceptConnectionYouGoal", 
        "randomPosition": 0, 
        "name": "Accept Connection", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "partnerInfo": 3
        }, 
        "entitiesToMake": [
            "clearNewRelationship", 
            "newRelationshipToRelationship"
        ], 
        "interactionKeys": [
            "self"
        ], 
        "goalMenuKey": "acceptConnectionYouMenu", 
        "timeToDeath": 300
    }, 
    "complimentSwarmYouMine": {
        "resourceCount": 3, 
        "name": "Compliment", 
        "image": "tower_memoryRing", 
        "key": "complimentSwarmYouMine", 
        "emotionTags": [
            "joy", 
            "self", 
            "complimentSmall"
        ], 
        "resourceKeys": [
            "complimentSmall"
        ], 
        "activeImage": "tower_memoryRing_activeOutline-0099ff", 
        "description": "makes complimentSmall"
    }, 
    "reachOutDone": {
        "buttonKey": "reachOutButton", 
        "flag": "reachOutDone", 
        "key": "reachOutDone"
    }, 
    "takeSupportTowerPlaced": {
        "y": 0, 
        "x": 0, 
        "tower": "takeSupportTower", 
        "sourceTrait": "you", 
        "key": "takeSupportTowerPlaced"
    }, 
    "callousnessTower": {
        "description": "Uses selfishness to calm anger, joy, sadness", 
        "charges": 5, 
        "image": "tower_numb", 
        "damage": 20, 
        "damageMultipliers": {
            "anger": 1, 
            "joy": 1, 
            "sadness": 1
        }, 
        "impulseTicks": 1, 
        "key": "callousnessTower", 
        "activeImage": "tower_numb_activeOutline-0099ff", 
        "name": "Callousness"
    }, 
    "worldGoalFocusPathStopComponent": {
        "currencyEffect": "starParticleEffect"
    }, 
    "reachOutGoal": {
        "key": "reachOutGoal", 
        "randomPosition": 0, 
        "name": "Reach Out To Someone", 
        "image": "goal_goalMeetNewPerson-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": [
            "hurtingPathClever", 
            "reachOutDone"
        ], 
        "goalMenuKey": "reachOutMenu"
    }, 
    "talkAboutYouButton": {
        "constructionKey": "talkAboutYouGoalConstruction", 
        "name": "Talk About You", 
        "image": "goal_newNote-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "talkAboutYouGoal", 
        "key": "talkAboutYouButton", 
        "interactionKeys": [
            "himself"
        ], 
        "description": [
            "Requires Info on You, social.", 
            "Makes calm."
        ]
    }, 
    "helpfulToInsecurity": {
        "sourceTrait": "helpful", 
        "newTrait": "insecurity", 
        "key": "helpfulToInsecurity"
    }, 
    "learnHistoryGoal": {
        "key": "learnHistoryGoal", 
        "randomPosition": 0, 
        "name": "Learn His History", 
        "image": "goal_goalAskAbout-000000", 
        "currencyRequested": {
            "support_you": 3
        }, 
        "entitiesToMake": "flipHurt", 
        "goalMenuKey": "learnHistoryMenu"
    }, 
    "chapter1": {
        "chapterCount": 1, 
        "makeOnCreateEntities": [
            "you", 
            "worthless", 
            "him", 
            "restless", 
            "capable", 
            "startPaths", 
            "choreMaker", 
            "selfish", 
            "selfishPathHim", 
            "strong", 
            "restlessPathStrong", 
            "clever", 
            "cleverPathRestless"
        ], 
        "name": "Chapter 1 - chapter1", 
        "key": "chapter1", 
        "goalsToCheck": [
            "nullEntity"
        ]
    }, 
    "caringButton": {
        "aiVal": 1, 
        "constructionKey": "caringTowerConstruction", 
        "name": "Caring", 
        "image": "tower_minePain", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "caringTower", 
        "limitingKeys": [
            "caringTower", 
            "caringTowerConstruction"
        ], 
        "key": "caringButton", 
        "subPanel": "Towers", 
        "description": "Converts goodness -> caring"
    }, 
    "partnerInfo": {
        "name": "Info on Partner", 
        "key": "partnerInfo", 
        "tags": [
            "partnerInfo"
        ]
    }, 
    "hisGoodWorkToHisWork": {
        "sourceTrait": "hisGoodWork", 
        "newTrait": "hisWork", 
        "key": "hisGoodWorkToHisWork"
    }, 
    "openUpBranch": {
        "flagToCheck": "openUpDone", 
        "key": "openUpBranch", 
        "notFlagEntities": "openUpButton"
    }, 
    "criticismSwarmYouMine": {
        "resourceCount": 3, 
        "name": "Criticism", 
        "image": "tower_eyeTear", 
        "key": "criticismSwarmYouMine", 
        "emotionTags": [
            "sadness", 
            "self", 
            "criticismSmall"
        ], 
        "resourceKeys": [
            "criticismSmall"
        ], 
        "activeImage": "tower_eyeTear_activeOutline-0099ff", 
        "description": "makes criticismSmall"
    }, 
    "slowWorkFlat": {
        "resourceCount": 1, 
        "name": "Slow Work", 
        "image": "tower_memoryDefineSelf", 
        "destination": "himself", 
        "key": "slowWorkFlat", 
        "emotionTags": [
            "anger"
        ], 
        "resourceKeys": "slowWorkMed", 
        "activeImage": "tower_memoryDefineSelf_activeOutline-0099ff"
    }, 
    "hisGraciousGoal": {
        "key": "hisGraciousGoal", 
        "randomPosition": 1, 
        "name": "Be Gracious For Help", 
        "makeOnTimeOut": "worthlessFeel", 
        "image": "goal_butterfly-000000", 
        "currencyRequested": {
            "social": 3
        }, 
        "entitiesToMake": "tiredSwarmHim", 
        "goalMenuKey": "hisGraciousMenu", 
        "timeToDeath": 300
    }, 
    "him": {
        "sector": [
            6, 
            6
        ], 
        "name": "Him", 
        "aliveEntities": {
            "needWorkGoal": 5
        }, 
        "image": "trait-993399", 
        "personHeld": "him", 
        "isaacEntities": [
            "callousnessButton"
        ], 
        "key": "him", 
        "interactionKeys": [
            "himself"
        ], 
        "maxLevel": 8, 
        "startManagedEntities": [
            "himEntities"
        ], 
        "tendPosition": [
            10, 
            20
        ]
    }, 
    "flirtButton": {
        "constructionKey": "flirtTowerConstruction", 
        "name": "Flirtation", 
        "image": "tower_towerFlirt", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "flirtTower", 
        "limitingKeys": [
            "flirtTower", 
            "flirtTowerConstruction"
        ], 
        "key": "flirtButton", 
        "subPanel": "Towers", 
        "interactionKeys": [
            "self"
        ], 
        "description": [
            "It's just hard for you", 
            "Converts openness -> flirtation"
        ]
    }, 
    "doUsefulGoal": {
        "key": "doUsefulGoal", 
        "randomPosition": 1, 
        "name": "Do Useful Thing", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": "switchThankGoal", 
        "goalMenuKey": "doUsefulMenu"
    }, 
    "crueltyTower": {
        "image": "tower_goalDisavowal-000000", 
        "activeImage": "tower_goalDisavowal-000000_activeOutline-0099ff", 
        "name": "Cruelty", 
        "key": "crueltyTower", 
        "description": "Converts frustration -> cruelty"
    }, 
    "noSupportGoal": {
        "key": "noSupportGoal", 
        "randomPosition": 1, 
        "name": "Give Him No Support", 
        "image": "goal_goalDisavowal-000000", 
        "description": [
            "You didn't give him your full support this time, but can you keep", 
            "yourself from giving him anything?"
        ], 
        "currencyRequested": {
            "cruelty": 3
        }, 
        "entitiesToMake": "aloneFlatHim", 
        "goalMenuKey": "noSupportMenu", 
        "timeToDeath": 150
    }, 
    "faithCrisis_ext": {
        "personHeld": "him", 
        "image": [
            "trait-660000", 
            "trait-5B0000", 
            "trait-700000"
        ], 
        "name": "Crisis of Faith", 
        "key": "faithCrisis_ext", 
        "sourceKey": "faithCrisis"
    }, 
    "reinforceViceMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Reinforce Vices", 
        "key": "reinforceViceMenu"
    }, 
    "workHappy": {
        "resourceCount": 1, 
        "name": "Happiness at Work", 
        "image": "tower_memoryRing", 
        "destination": "himself", 
        "key": "workHappy", 
        "emotionTags": [
            "joy"
        ], 
        "resourceKeys": "workWinSmall", 
        "activeImage": "tower_memoryRing_activeOutline-0099ff"
    }, 
    "worthlessMed": {
        "emotion": "sadness", 
        "name": "worthlessness", 
        "image": "creepLarge-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 60, 
        "key": "worthlessMed"
    }, 
    "himPathHimself": {
        "startKey": "him", 
        "endKey": "himself", 
        "key": "himPathHimself"
    }, 
    "opennessDeposit": {
        "timeToDeath": 120, 
        "image": "tower_weight", 
        "deposit": {
            "openness": 3
        }, 
        "key": "opennessDeposit", 
        "activeImage": "tower_weight_activeOutline-0099ff", 
        "name": "Openness"
    }, 
    "stupid": {
        "name": "stupidity", 
        "key": "stupid", 
        "tags": [
            "stupid"
        ]
    }, 
    "generousButton": {
        "constructionKey": "generousTowerConstruction", 
        "name": "Be Generous", 
        "image": "tower_newNote", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "generousTower", 
        "limitingKeys": [
            "generousTower", 
            "generousTowerConstruction"
        ], 
        "key": "generousButton", 
        "subPanel": "Towers", 
        "description": "Converts cheer -> generosity"
    }, 
    "compliment": {
        "name": "compliment", 
        "key": "compliment", 
        "tags": [
            "compliment"
        ]
    }, 
    "activity": {
        "name": "activity", 
        "key": "activity", 
        "tags": [
            "activity"
        ]
    }, 
    "jealousyBurstMine": {
        "resourceCount": 1, 
        "name": "Jealousy", 
        "image": "tower_depositSin", 
        "key": "jealousyBurstMine", 
        "emotionTags": [
            "self", 
            "anger"
        ], 
        "resourceKeys": [
            "anger"
        ], 
        "activeImage": "tower_depositSin_activeOutline-0099ff", 
        "description": "makes anger"
    }, 
    "memory_shameBurst": {
        "image": "trait-013d70", 
        "memoryEmotions": [
            "sadness"
        ], 
        "key": "memory_shameBurst", 
        "name": "Burst of Shame"
    }, 
    "flashback_complimentSmallConstruction": {
        "key": "flashback_complimentSmallConstruction", 
        "constructionIdentifier": "flashback_complimentSmall", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "guiltEmo": {
        "youKeys": "guiltEmoFlat", 
        "key": "guiltEmo", 
        "himKeys": "guiltFlatYou"
    }, 
    "killConnectFriendsButton": {
        "entitiesToKill": [
            "connectFriendsButton"
        ], 
        "key": "killConnectFriendsButton"
    }, 
    "lostControl": {
        "name": "lostControl", 
        "key": "lostControl"
    }, 
    "pushInsecurityMenu": {
        "image": "goal_drive-000000", 
        "completeText": [
            "He seems a little sad out of sympathy, but he never actually gets it.", 
            "You feel a little calmer though."
        ], 
        "name": "COMPLETED - Push Insecurity", 
        "key": "pushInsecurityMenu"
    }, 
    "convinceActivityGoal": {
        "key": "convinceActivityGoal", 
        "randomPosition": 1, 
        "name": "Convince To Try Activity", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "activity": 3
        }, 
        "entitiesToMake": [
            "vice", 
            "valueDeposit"
        ], 
        "goalMenuKey": "convinceActivityMenu"
    }, 
    "connectHurtGoalConstruction": {
        "key": "connectHurtGoalConstruction", 
        "constructionIdentifier": "connectHurtGoal", 
        "name": "Constructing - Connect To Your Hurt", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Connect To Your Hurt", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "strengthDeposit": {
        "image": "tower_weight", 
        "activeImage": "tower_weight_activeOutline-0099ff", 
        "name": "Strength", 
        "key": "strengthDeposit", 
        "deposit": {
            "strength": 3
        }
    }, 
    "explainFindHelpFail": {
        "completeText": "Maybe a better person would have found something, but you did not.", 
        "key": "explainFindHelpFail"
    }, 
    "worldGoal": {
        "minSelfDist": 4
    }, 
    "willMine": {
        "image": "tower_mineWill", 
        "resourceKeys": [
            "will"
        ], 
        "name": "Drive", 
        "key": "willMine", 
        "activeImage": "tower_mineWill_activeOutline-0099ff"
    }, 
    "connectFriendsMenu": {
        "image": "goal_mineSocial-000000", 
        "name": "COMPLETED - Connect to Old Friends", 
        "key": "connectFriendsMenu"
    }, 
    "oldHurt": {
        "emotionsToAdd": {
            "oldFailSmall": 3
        }, 
        "name": "Old Pain", 
        "image": "tower_eyeTear", 
        "key": "oldHurt", 
        "memoryKey": "memory_oldHurt", 
        "emotionTags": [
            "sadness", 
            "self"
        ], 
        "resourceKey": "oldHurtMineConstruction", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "strongPathMature": {
        "startKey": "strong", 
        "endKey": "mature", 
        "key": "strongPathMature"
    }, 
    "memoryGoal": {
        "minSelfDist": 4
    }, 
    "worthlessSmall": {
        "emotion": "sadness", 
        "name": "worthlessness", 
        "image": "creep-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 20, 
        "key": "worthlessSmall"
    }, 
    "goodnessMine": {
        "name": "Goodness", 
        "image": "tower_newNote", 
        "key": "goodnessMine", 
        "resourceKeys": [
            "goodness"
        ], 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "description": "Why is this exhaustible? What does that say about it?"
    }, 
    "relationBranch": {
        "flagToCheck": "relation", 
        "key": "relationBranch", 
        "notFlagEntities": [
            "newRelationship", 
            "setRelation"
        ]
    }, 
    "getOverBadWorkGoalConstruction": {
        "key": "getOverBadWorkGoalConstruction", 
        "constructionIdentifier": "getOverBadWorkGoal", 
        "name": "Constructing - Get Over Bad Work", 
        "image": "trait-aaaaaa99_goal_weight-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Get Over Bad Work", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "friendMeditateAction": {
        "currenciesRequired": [
            "social_warm"
        ], 
        "towerKey": "friendMeditateTower", 
        "currenciesToMake": [
            "calm"
        ], 
        "name": "Calm", 
        "key": "friendMeditateAction"
    }, 
    "completeWorkGoalConstruction": {
        "key": "completeWorkGoalConstruction", 
        "constructionIdentifier": "completeWorkGoal", 
        "name": "Constructing - Complete Work", 
        "image": "trait-aaaaaa99_goal_trophy-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Complete Work", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "anxietyMine": {
        "image": "tower_mineCaution", 
        "resourceKeys": [
            "anxiety"
        ], 
        "name": "Anxiety", 
        "key": "anxietyMine", 
        "activeImage": "tower_mineCaution_activeOutline-0099ff"
    }, 
    "makeOldFailSwarmGoal": {
        "key": "makeOldFailSwarmGoal", 
        "randomPosition": 0, 
        "name": "Make Swarm About Old Failures", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "oldFail": 3, 
            "swarm": 3
        }, 
        "entitiesToMake": "oldFailSwarm", 
        "goalMenuKey": "makeOldFailSwarmMenu"
    }, 
    "soberDownGoal": {
        "key": "soberDownGoal", 
        "randomPosition": 1, 
        "name": "Sober Down", 
        "image": "goal_goalCalmDown-000000", 
        "currencyRequested": {
            "meditation": 3
        }, 
        "entitiesToMake": "flipMature", 
        "goalMenuKey": "soberDownMenu"
    }, 
    "socialMineButton": {
        "constructionKey": "socialMineConstruction", 
        "name": "Social", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_mineSocial", 
        "currenciesMade": [
            "social"
        ], 
        "entityKey": "socialMine", 
        "limitingKeys": [
            "socialMine", 
            "socialMineConstruction"
        ], 
        "key": "socialMineButton", 
        "interactionKeys": [
            "himself"
        ], 
        "description": "makes social"
    }, 
    "tempTrait_ext": {
        "image": [
            "trait-ffffff", 
            "trait-E5E5E5", 
            "trait-FFFFFF"
        ], 
        "name": "temp", 
        "key": "tempTrait_ext", 
        "sourceKey": "tempTrait"
    }, 
    "guiltGoal": {
        "key": "guiltGoal", 
        "randomPosition": 0, 
        "name": "Guilt Partner", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "need": 3
        }, 
        "entitiesToMake": "guiltEmo", 
        "goalMenuKey": "guiltMenu", 
        "description": "It is hard that he never helps when things hurt."
    }, 
    "needHelpGoalConstruction": {
        "key": "needHelpGoalConstruction", 
        "constructionIdentifier": "needHelpGoal", 
        "name": "Constructing - Need Help Yourself", 
        "image": "trait-aaaaaa99_goal_minePain-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Need Help Yourself", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "state": {
        "name": "state", 
        "key": "state", 
        "tags": [
            "state"
        ]
    }, 
    "viceTower": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Indulge Vice", 
        "key": "viceTower", 
        "description": "Converts social + energy -> vice"
    }, 
    "worthless_ext": {
        "personHeld": "you", 
        "image": [
            "trait-3399cc", 
            "trait-2D89B7", 
            "trait-38A8E0"
        ], 
        "name": "Worthlessness", 
        "key": "worthless_ext", 
        "sourceKey": "worthless"
    }, 
    "selfDistractionButton": {
        "constructionKey": "selfDistractionTowerConstruction", 
        "name": "Distracting Yourself", 
        "image": "tower_mineWill", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "selfDistractionTower", 
        "limitingKeys": [
            "selfDistractionTower", 
            "selfDistractionTowerConstruction"
        ], 
        "key": "selfDistractionButton", 
        "subPanel": "Towers", 
        "description": "Converts anxiety -> will"
    }, 
    "pushTower": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Push At Him", 
        "key": "pushTower", 
        "description": [
            "He might think he's happier not thinking about it, but this is for his own good.", 
            "Converts cruelty + social -> push"
        ]
    }, 
    "dreamDeathMajor": {
        "resourceCount": 1, 
        "name": "Death Of A Dream", 
        "image": "tower_depositSin", 
        "destination": "himself", 
        "key": "dreamDeathMajor", 
        "emotionTags": [
            "sadness"
        ], 
        "resourceKeys": "dreamDeathLarge", 
        "activeImage": "tower_depositSin_activeOutline-0099ff"
    }, 
    "takeConnectGoalConstruction": {
        "key": "takeConnectGoalConstruction", 
        "constructionIdentifier": "takeConnectGoal", 
        "name": "Constructing - Take Friend's Connection", 
        "image": "trait-aaaaaa99_goal_goalMeetNewPerson-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Take Friend's Connection", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "socialMine": {
        "image": "tower_mineSocial", 
        "resourceKeys": [
            "social"
        ], 
        "name": "Social", 
        "key": "socialMine", 
        "activeImage": "tower_mineSocial_activeOutline-0099ff"
    }, 
    "needWorkMenu": {
        "image": "goal_drive-000000", 
        "name": "COMPLETED - Need To Do Good Work", 
        "key": "needWorkMenu"
    }, 
    "speakOfValueButton": {
        "constructionKey": "speakOfValueGoalConstruction", 
        "name": "Speak of Your Value", 
        "image": "goal_mineCheer-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "speakOfValueGoal", 
        "key": "speakOfValueButton", 
        "description": "Requires will."
    }, 
    "funPathRelationship": {
        "startKey": "fun", 
        "endKey": "relationship", 
        "key": "funPathRelationship"
    }, 
    "supportCrisisMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Support Partner", 
        "key": "supportCrisisMenu"
    }, 
    "resentYou": {
        "emotionsToAdd": {
            "resentMed": 1
        }, 
        "name": "Resent Your Failures", 
        "image": "tower_discard", 
        "key": "resentYou", 
        "memoryKey": "memory_resentYou", 
        "emotionTags": [
            "anger", 
            "self"
        ], 
        "resourceKey": "resentYouMineConstruction", 
        "activeImage": "tower_discard_activeOutline-0099ff"
    }, 
    "joyBurstMine": {
        "resourceCount": 1, 
        "name": "Joy", 
        "image": "tower_mineCheer", 
        "key": "joyBurstMine", 
        "emotionTags": [
            "self", 
            "joy"
        ], 
        "resourceKeys": [
            "joy"
        ], 
        "activeImage": "tower_mineCheer_activeOutline-0099ff", 
        "description": "makes joy"
    }, 
    "support_you": {
        "name": "support", 
        "key": "support_you", 
        "tags": [
            "support_you"
        ]
    }, 
    "talkAboutYouMenu": {
        "image": "goal_newNote-000000", 
        "name": "COMPLETED - Talk About You", 
        "key": "talkAboutYouMenu"
    }, 
    "overcomeCrisisGoalConstruction": {
        "key": "overcomeCrisisGoalConstruction", 
        "constructionIdentifier": "overcomeCrisisGoal", 
        "name": "Constructing - Overcome Crisis", 
        "image": "trait-aaaaaa99_goal_motivation-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Overcome Crisis", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "flashback_aloneMedConstruction": {
        "key": "flashback_aloneMedConstruction", 
        "constructionIdentifier": "flashback_aloneMed", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "supportNeedTower": {
        "image": "tower_heart", 
        "activeImage": "tower_heart_activeOutline-0099ff", 
        "name": "Support", 
        "key": "supportNeedTower", 
        "description": "Converts need -> support"
    }, 
    "obsessionsAction": {
        "currenciesRequired": [
            "obsession"
        ], 
        "towerKey": "obsessionsTower", 
        "name": "Obsessions", 
        "key": "obsessionsAction"
    }, 
    "spendTimeWarmButton": {
        "constructionKey": "spendTimeWarmGoalConstruction", 
        "name": "Spend Time", 
        "image": "goal_mineCheer-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "spendTimeWarmGoal", 
        "key": "spendTimeWarmButton", 
        "description": "Requires will."
    }, 
    "painMine": {
        "image": "tower_pain", 
        "resourceKeys": [
            "pain"
        ], 
        "name": "Pain Mine", 
        "key": "painMine", 
        "activeImage": "tower_pain_activeOutline-0099ff"
    }, 
    "swarmTowerConstruction": {
        "key": "swarmTowerConstruction", 
        "constructionIdentifier": "swarmTower", 
        "name": "Constructing - Swarm", 
        "image": "trait-aaaaaa99_tower_newNote", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Swarm", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "findHelpMenu": {
        "image": "goal_heart-000000", 
        "completeText": "Sometimes you can find something.", 
        "name": "COMPLETED - Find Way To Be Helpful", 
        "key": "findHelpMenu"
    }, 
    "exploreStrengthMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Explore His Strength", 
        "key": "exploreStrengthMenu"
    }, 
    "accuseSelfishGoal": {
        "key": "accuseSelfishGoal", 
        "randomPosition": 0, 
        "name": "Accuse of Selfishness", 
        "image": "goal_goalAskAbout-000000", 
        "currencyRequested": {
            "cruelty": 3, 
            "social": 3
        }, 
        "entitiesToMake": {
            "flipGood": 50
        }, 
        "goalMenuKey": "accuseSelfishMenu"
    }, 
    "cheerMineConstruction": {
        "key": "cheerMineConstruction", 
        "constructionIdentifier": "cheerMine", 
        "name": "Constructing - Cheer Mine", 
        "image": "trait-aaaaaa99_tower_mineCheer", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Cheer Mine", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "makeOldFailFlatGoal": {
        "key": "makeOldFailFlatGoal", 
        "randomPosition": 0, 
        "name": "Make Statement of Old Failures", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "oldFail": 3, 
            "state": 3
        }, 
        "entitiesToMake": "oldFailFlat", 
        "goalMenuKey": "makeOldFailFlatMenu"
    }, 
    "calmnessMine": {
        "name": "Calmness", 
        "image": "tower_wave", 
        "key": "calmnessMine", 
        "resourceKeys": [
            "calm"
        ], 
        "activeImage": "tower_wave_activeOutline-0099ff", 
        "description": "You can't help but feel better around The Warm Friend"
    }, 
    "doUsefulMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Do Useful Thing", 
        "key": "doUsefulMenu"
    }, 
    "getOverGoodWorkGoal": {
        "key": "getOverGoodWorkGoal", 
        "randomPosition": 0, 
        "name": "Get Over Good Work", 
        "image": "goal_weight-000000", 
        "currencyRequested": {
            "will": 1
        }, 
        "entitiesToMake": "hisGoodWorkToHisWork", 
        "goalMenuKey": "getOverGoodWorkMenu"
    }, 
    "appreciateWorkGoal": {
        "key": "appreciateWorkGoal", 
        "randomPosition": 0, 
        "name": "Appreciate His Work", 
        "image": "goal_towerFlirt-000000", 
        "currencyRequested": {
            "workTopic": 3, 
            "social": 3
        }, 
        "entitiesToMake": "complimentSwarm", 
        "goalMenuKey": "appreciateWorkMenu"
    }, 
    "youInfoDeposit": {
        "image": "tower_insecure", 
        "activeImage": "tower_insecure_activeOutline-0099ff", 
        "name": "Info on You", 
        "key": "youInfoDeposit", 
        "deposit": {
            "youInfo": 3
        }
    }, 
    "talkAboutHimMenu": {
        "image": "goal_newNote-000000", 
        "name": "COMPLETED - Talk About Him", 
        "key": "talkAboutHimMenu"
    }, 
    "probedProblem": {
        "name": "probed problem", 
        "key": "probedProblem", 
        "tags": [
            "probedProblem"
        ]
    }, 
    "memory_viceFlatYou": {
        "image": "trait-e6e617", 
        "memoryEmotions": [
            "joy"
        ], 
        "key": "memory_viceFlatYou", 
        "name": "Vice"
    }, 
    "searchingWorthToHelpful": {
        "sourceTrait": "searchingWorth", 
        "newTrait": "helpful", 
        "key": "searchingWorthToHelpful"
    }, 
    "flashback_complimentMed": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_complimentMed", 
        "emotionTags": "complimentMed", 
        "resourceKeys": [
            "complimentMed"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes complimentMed"
    }, 
    "flashback_anger": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_anger", 
        "emotionTags": "anger", 
        "resourceKeys": [
            "anger"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes anger"
    }, 
    "complimentFlatYouMine": {
        "resourceCount": 1, 
        "name": "Compliment", 
        "image": "tower_memoryRing", 
        "key": "complimentFlatYouMine", 
        "emotionTags": [
            "joy", 
            "self", 
            "complimentMed"
        ], 
        "resourceKeys": [
            "complimentMed"
        ], 
        "activeImage": "tower_memoryRing_activeOutline-0099ff", 
        "description": "makes complimentMed"
    }, 
    "probeTopicMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Probe Topic", 
        "key": "probeTopicMenu"
    }, 
    "selfishnessMine": {
        "name": "Selfishness", 
        "image": "tower_depositSin", 
        "key": "selfishnessMine", 
        "resourceKeys": [
            "selfishness"
        ], 
        "activeImage": "tower_depositSin_activeOutline-0099ff", 
        "description": "Why is this exhaustible? What does that say about it?"
    }, 
    "flirtAction": {
        "currenciesRequired": [
            "openness"
        ], 
        "towerKey": "flirtTower", 
        "currenciesToMake": [
            "flirtation"
        ], 
        "name": "Flirt", 
        "key": "flirtAction"
    }, 
    "socialButton": {
        "constructionKey": "socialTowerConstruction", 
        "name": "Social", 
        "image": "tower_mineSocial", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "socialTower", 
        "limitingKeys": [
            "socialTower", 
            "socialTowerConstruction"
        ], 
        "key": "socialButton", 
        "subPanel": "Towers", 
        "interactionKeys": [
            "self"
        ], 
        "description": "Converts openness -> social"
    }, 
    "flashback_sadnessConstruction": {
        "key": "flashback_sadnessConstruction", 
        "constructionIdentifier": "flashback_sadness", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "himSupportTower": {
        "image": "tower_dependence", 
        "activeImage": "tower_dependence_activeOutline-0099ff", 
        "name": "Support", 
        "key": "himSupportTower", 
        "description": "Converts strength -> support"
    }, 
    "flipClever": {
        "trait2": "warm", 
        "trait1": "clever", 
        "key": "flipClever"
    }, 
    "generousTowerConstruction": {
        "key": "generousTowerConstruction", 
        "constructionIdentifier": "generousTower", 
        "name": "Constructing - Be Generous", 
        "image": "trait-aaaaaa99_tower_newNote", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Be Generous", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "thinkMine": {
        "image": "tower_mineThought", 
        "resourceKeys": [
            "thought"
        ], 
        "name": "Think About Helping", 
        "key": "thinkMine", 
        "activeImage": "tower_mineThought_activeOutline-0099ff"
    }, 
    "indulgeViceGoal": {
        "key": "indulgeViceGoal", 
        "randomPosition": 0, 
        "name": "Indulge Vice", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 1
        }, 
        "goalMenuKey": "indulgeViceMenu"
    }, 
    "pushAction": {
        "currenciesRequired": [
            "cruelty", 
            "social"
        ], 
        "towerKey": "pushTower", 
        "currenciesToMake": [
            "push"
        ], 
        "name": "Push", 
        "key": "pushAction"
    }, 
    "openness": {
        "name": "openness", 
        "key": "openness", 
        "tags": [
            "openness"
        ]
    }, 
    "helpful_ext": {
        "personHeld": "you", 
        "image": [
            "trait-887788", 
            "trait-7A6B7A", 
            "trait-958295"
        ], 
        "name": "Helpful", 
        "key": "helpful_ext", 
        "sourceKey": "helpful"
    }, 
    "talkAboutHimButton": {
        "constructionKey": "talkAboutHimGoalConstruction", 
        "name": "Talk About Him", 
        "image": "goal_newNote-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "talkAboutHimGoal", 
        "key": "talkAboutHimButton", 
        "description": "Requires Info on Partner, social."
    }, 
    "flirtYouMenu": {
        "image": "goal_heart-000000", 
        "completeText": [
            "Words just come tumbling out of him, but there's stuff he's making", 
            "sure not to tell you."
        ], 
        "name": "COMPLETED - Flirt", 
        "key": "flirtYouMenu"
    }, 
    "caring": {
        "name": "caring", 
        "key": "caring", 
        "tags": [
            "caring"
        ]
    }, 
    "worthless": {
        "sector": [
            5, 
            8
        ], 
        "name": "Worthlessness", 
        "image": "trait-3399cc", 
        "personHeld": "you", 
        "isaacEntities": [
            "forceOpennessButton", 
            "youRelationButtonBranch"
        ], 
        "key": "worthless", 
        "interactionKeys": [
            "self"
        ], 
        "startManagedEntities": [
            "insecureMine", 
            "insecureMine"
        ]
    }, 
    "helpValueButton": {
        "constructionKey": "helpValueTowerConstruction", 
        "name": "Value From Help", 
        "image": "tower_trophy", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "helpValueTower", 
        "limitingKeys": [
            "helpValueTower", 
            "helpValueTowerConstruction"
        ], 
        "key": "helpValueButton", 
        "subPanel": "Towers", 
        "description": "Converts helped -> value"
    }, 
    "opennessAction": {
        "currenciesRequired": [
            "will"
        ], 
        "towerKey": "opennessTower", 
        "currenciesToMake": [
            "openness"
        ], 
        "name": "Open!", 
        "key": "opennessAction"
    }, 
    "trySomethingButton": {
        "constructionKey": "trySomethingGoalConstruction", 
        "name": "Try Something New", 
        "image": "goal_trophy-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "trySomethingGoal", 
        "key": "trySomethingButton", 
        "interactionKeys": [
            "himself"
        ], 
        "description": "Requires will."
    }, 
    "capable": {
        "sector": [
            0, 
            8
        ], 
        "name": "His Capability", 
        "startManagedEntities": [
            "busyWorkMine", 
            "busyWorkMine"
        ], 
        "personHeld": "him", 
        "key": "capable", 
        "interactionKeys": [
            "himself"
        ], 
        "maxLevel": 3, 
        "image": "trait-ccffcc"
    }, 
    "flashback_resentMedConstruction": {
        "key": "flashback_resentMedConstruction", 
        "constructionIdentifier": "flashback_resentMed", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "interestingEmo": {
        "youKeys": "aloneFlatYou", 
        "key": "interestingEmo", 
        "himKeys": "aloneFlatHim"
    }, 
    "flashback_worthlessMedConstruction": {
        "key": "flashback_worthlessMedConstruction", 
        "constructionIdentifier": "flashback_worthlessMed", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "reinforceViceGoal": {
        "key": "reinforceViceGoal", 
        "randomPosition": 1, 
        "name": "Reinforce Vices", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "vice": 1
        }, 
        "entitiesToMake": "viceSwarm", 
        "goalMenuKey": "reinforceViceMenu", 
        "timeToDeath": 30
    }, 
    "beHelpMenu": {
        "image": "goal_heart-000000", 
        "name": "COMPLETED - Be Helpful", 
        "key": "beHelpMenu"
    }, 
    "reachOutGoalConstruction": {
        "key": "reachOutGoalConstruction", 
        "constructionIdentifier": "reachOutGoal", 
        "name": "Constructing - Reach Out To Someone", 
        "image": "trait-aaaaaa99_goal_goalMeetNewPerson-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Reach Out To Someone", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "disciplinePathHim": {
        "startKey": "discipline", 
        "endKey": "him", 
        "key": "disciplinePathHim"
    }, 
    "makeComplimentFlatMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Make Complimentary Statement", 
        "key": "makeComplimentFlatMenu"
    }, 
    "maturePathHisWork": {
        "startKey": "mature", 
        "endKey": "hisWork", 
        "key": "maturePathHisWork"
    }, 
    "learnHimGoalConstruction": {
        "key": "learnHimGoalConstruction", 
        "constructionIdentifier": "learnHimGoal", 
        "name": "Constructing - Learn About Him", 
        "image": "trait-aaaaaa99_goal_book-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Learn About Him", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "learnHimMenu": {
        "image": "goal_book-000000", 
        "completeText": "That's something new", 
        "name": "COMPLETED - Learn About Him", 
        "key": "learnHimMenu"
    }, 
    "insecureSwarmYouMine": {
        "resourceCount": 3, 
        "name": "Insecurities", 
        "image": "tower_eyeTear", 
        "key": "insecureSwarmYouMine", 
        "emotionTags": [
            "sadness", 
            "self", 
            "insecureSmall"
        ], 
        "resourceKeys": [
            "insecureSmall"
        ], 
        "activeImage": "tower_eyeTear_activeOutline-0099ff", 
        "description": "makes insecureSmall"
    }, 
    "findHelpResult": {
        "goodEntities": {
            "beHelpGoal": 2
        }, 
        "badEntities": "explainFindHelpFail", 
        "key": "findHelpResult"
    }, 
    "dailyHelpInfoPanel": {
        "components": [
            "dailyEntityMakerComponent"
        ], 
        "helpLines": [
            "These are the sources of the recurring goals in your life."
        ], 
        "name": "Recurring Chores", 
        "key": "dailyHelpInfoPanel"
    }, 
    "needPainButton": {
        "constructionKey": "needPainTowerConstruction", 
        "name": "Need Help", 
        "image": "tower_droop", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "needPainTower", 
        "limitingKeys": [
            "needPainTower", 
            "needPainTowerConstruction"
        ], 
        "key": "needPainButton", 
        "description": "Converts pain -> need"
    }, 
    "talkAboutHimGoalConstruction": {
        "key": "talkAboutHimGoalConstruction", 
        "constructionIdentifier": "talkAboutHimGoal", 
        "name": "Constructing - Talk About Him", 
        "image": "trait-aaaaaa99_goal_newNote-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Talk About Him", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "quietTimeButton": {
        "constructionKey": "quietTimeGoalConstruction", 
        "name": "Quiet Time Together", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "quietTimeGoal", 
        "key": "quietTimeButton", 
        "description": [
            "Requires social.", 
            "Makes Info on You.", 
            "Makes calm."
        ]
    }, 
    "flirtResult": {
        "goodEntities": [
            "youInfoDeposit", 
            "partnerInfoDeposit"
        ], 
        "key": "flirtResult"
    }, 
    "makeSlowWorkFlatGoal": {
        "key": "makeSlowWorkFlatGoal", 
        "randomPosition": 0, 
        "name": "Make Statement About Slow Work", 
        "image": "goal_mineFrustration-000000", 
        "currencyRequested": {
            "slowWork": 3, 
            "state": 3
        }, 
        "entitiesToMake": "slowWorkFlat", 
        "goalMenuKey": "makeSlowWorkFlatMenu"
    }, 
    "completeWorkMenu": {
        "image": "goal_trophy-000000", 
        "name": "COMPLETED - Complete Work", 
        "key": "completeWorkMenu"
    }, 
    "worker": {
        "planeOfExistence": "path"
    }, 
    "connectHurtDone": {
        "buttonKey": "connectHurtButton", 
        "flag": "connectHurtDone", 
        "key": "connectHurtDone"
    }, 
    "complimentSmall": {
        "emotion": "joy", 
        "name": "compliment", 
        "image": "creep-ffff00", 
        "memoryImage": "memoryJoy", 
        "health": 20, 
        "key": "complimentSmall"
    }, 
    "getOverBadWorkGoal": {
        "key": "getOverBadWorkGoal", 
        "randomPosition": 0, 
        "name": "Get Over Bad Work", 
        "image": "goal_weight-000000", 
        "currencyRequested": {
            "will": 6
        }, 
        "entitiesToMake": "hisBadWorkToHisWork", 
        "goalMenuKey": "getOverBadWorkMenu"
    }, 
    "supportTower": {
        "image": "tower_dependence", 
        "activeImage": "tower_dependence_activeOutline-0099ff", 
        "name": "Support", 
        "key": "supportTower", 
        "description": "Converts cheer -> support"
    }, 
    "askForBeliefMenu": {
        "image": "goal_trophy-000000", 
        "name": "COMPLETED - Ask For Belief", 
        "key": "askForBeliefMenu"
    }, 
    "insecureSmall": {
        "emotion": "sadness", 
        "name": "insecure", 
        "image": "creep-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 20, 
        "key": "insecureSmall"
    }, 
    "sharePainButton": {
        "constructionKey": "sharePainGoalConstruction", 
        "name": "Share Pain", 
        "image": "goal_minePain-000000", 
        "description": "Requires pain, social.", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "sharePainGoal", 
        "key": "sharePainButton", 
        "displayRiskIcon": 1
    }, 
    "findLifeHelpResult": {
        "goodEntities": "beHelpGoal", 
        "badEntities": [
            "hisGraciousGoal", 
            "hisGraciousGoal", 
            "hisGraciousGoal", 
            "hisGraciousGoal"
        ], 
        "key": "findLifeHelpResult"
    }, 
    "selfDistractionTower": {
        "image": "tower_mineWill", 
        "activeImage": "tower_mineWill_activeOutline-0099ff", 
        "name": "Distracting Yourself", 
        "key": "selfDistractionTower", 
        "description": "Converts anxiety -> will"
    }, 
    "hisGraciousMenu": {
        "image": "goal_butterfly-000000", 
        "name": "COMPLETED - Be Gracious For Help", 
        "key": "hisGraciousMenu"
    }, 
    "insecureSwarmHim": {
        "resourceCount": 3, 
        "name": "Your Insecurity", 
        "image": "tower_eyeTear", 
        "destination": "himself", 
        "key": "insecureSwarmHim", 
        "emotionTags": [
            "sadness"
        ], 
        "resourceKeys": "insecureSmall", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "pushButton": {
        "constructionKey": "pushTowerConstruction", 
        "name": "Push At Him", 
        "image": "tower_newNote", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "pushTower", 
        "limitingKeys": [
            "pushTower", 
            "pushTowerConstruction"
        ], 
        "key": "pushButton", 
        "subPanel": "Towers", 
        "description": [
            "He might think he's happier not thinking about it, but this is for his own good.", 
            "Converts cruelty + social -> push"
        ]
    }, 
    "valueDeposit": {
        "randomPosition": 0, 
        "timeToDeath": 120, 
        "image": "tower_trophy", 
        "deposit": {
            "value": 3
        }, 
        "key": "valueDeposit", 
        "interactionKeys": [
            "self"
        ], 
        "activeImage": "tower_trophy_activeOutline-0099ff", 
        "name": "Value"
    }, 
    "value": {
        "name": "value", 
        "key": "value", 
        "tags": [
            "value"
        ]
    }, 
    "will": {
        "name": "will", 
        "key": "will", 
        "tags": [
            "will"
        ]
    }, 
    "takeStrengthMenu": {
        "image": "goal_weight-000000", 
        "name": "COMPLETED - Take Strength From", 
        "key": "takeStrengthMenu"
    }, 
    "oldLifeMineConstruction": {
        "key": "oldLifeMineConstruction", 
        "constructionIdentifier": "oldLifeMine", 
        "name": "Reminder Of Your Old Life", 
        "image": "tower_eyeTear-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Reminder Of Your Old Life"
    }, 
    "caringTowerConstruction": {
        "key": "caringTowerConstruction", 
        "constructionIdentifier": "caringTower", 
        "name": "Constructing - Caring", 
        "image": "trait-aaaaaa99_tower_minePain", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Caring", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "worthlessHim": {
        "resourceCount": 1, 
        "name": "Worthless", 
        "image": "tower_numb", 
        "destination": "himself", 
        "key": "worthlessHim", 
        "emotionTags": [
            "sadness"
        ], 
        "resourceKeys": "worthlessMed", 
        "activeImage": "tower_numb_activeOutline-0099ff"
    }, 
    "feelUselessMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Feel Useless", 
        "key": "feelUselessMenu"
    }, 
    "fascinateButton": {
        "constructionKey": "fascinateGoalConstruction", 
        "name": "Fascinate The Clever Friend", 
        "image": "goal_spark-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "fascinateGoal", 
        "key": "fascinateButton", 
        "description": "Requires interesting."
    }, 
    "feelUselessGoal": {
        "key": "feelUselessGoal", 
        "randomPosition": 0, 
        "name": "Feel Useless", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 1
        }, 
        "entitiesToMake": "helpfulToInsecurity", 
        "goalMenuKey": "feelUselessMenu"
    }, 
    "reinforceStupidMenu": {
        "image": "goal_mineFrustration-000000", 
        "name": "COMPLETED - Reinforce Stupidity", 
        "key": "reinforceStupidMenu"
    }, 
    "viceButton": {
        "constructionKey": "viceTowerConstruction", 
        "name": "Indulge Vice", 
        "image": "tower_newNote", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "viceTower", 
        "limitingKeys": [
            "viceTower", 
            "viceTowerConstruction"
        ], 
        "key": "viceButton", 
        "subPanel": "Towers", 
        "description": "Converts social + energy -> vice"
    }, 
    "searchWorthButton": {
        "constructionKey": "searchWorthGoalConstruction", 
        "name": "Why Are You Like This?", 
        "image": "goal_memoryLearn-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "searchWorthGoal", 
        "key": "searchWorthButton", 
        "description": "Requires insecurity."
    }, 
    "flashback_complimentMedConstruction": {
        "key": "flashback_complimentMedConstruction", 
        "constructionIdentifier": "flashback_complimentMed", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "shameBurstMineConstruction": {
        "key": "shameBurstMineConstruction", 
        "constructionIdentifier": "shameBurstMine", 
        "name": "Burst of Shame", 
        "image": "tower_memoryShame-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Burst of Shame"
    }, 
    "insecureMine": {
        "image": "tower_insecure", 
        "resourceKeys": [
            "insecure"
        ], 
        "name": "Insecurity Well", 
        "key": "insecureMine", 
        "activeImage": "tower_insecure_activeOutline-0099ff"
    }, 
    "feelUselessButton": {
        "constructionKey": "feelUselessGoalConstruction", 
        "name": "Feel Useless", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "feelUselessGoal", 
        "key": "feelUselessButton", 
        "description": "Requires will."
    }, 
    "overcomeHurtMenu": {
        "image": "goal_dependence-000000", 
        "completeText": [
            "You breathe a little better now, but he seems to have filled the", 
            "space you once held."
        ], 
        "name": "COMPLETED - Overcome Hurt", 
        "key": "overcomeHurtMenu"
    }, 
    "meditativeMine": {
        "image": "tower_goalCalmDown-000000", 
        "resourceKeys": [
            "meditation"
        ], 
        "name": "Meditation", 
        "key": "meditativeMine", 
        "activeImage": "tower_goalCalmDown-000000_activeOutline-0099ff"
    }, 
    "defineRoleButton": {
        "constructionKey": "defineRoleGoalConstruction", 
        "name": "Define Roles", 
        "image": "goal_puzzle-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "defineRoleGoal", 
        "key": "defineRoleButton", 
        "description": "Requires social."
    }, 
    "sharePainGoalConstruction": {
        "key": "sharePainGoalConstruction", 
        "constructionIdentifier": "sharePainGoal", 
        "name": "Constructing - Share Pain", 
        "image": "trait-aaaaaa99_goal_minePain-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Share Pain", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "memory_oldLife": {
        "image": "trait-013d70", 
        "memoryEmotions": [
            "sadness"
        ], 
        "key": "memory_oldLife", 
        "name": "Reminder Of Your Old Life"
    }, 
    "fishComplimentsGoalConstruction": {
        "key": "fishComplimentsGoalConstruction", 
        "constructionIdentifier": "fishComplimentsGoal", 
        "name": "Constructing - Fish For Compliments", 
        "image": "trait-aaaaaa99_goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Fish For Compliments", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "beSupportedGoalConstruction": {
        "key": "beSupportedGoalConstruction", 
        "constructionIdentifier": "beSupportedGoal", 
        "name": "Constructing - Take Support", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Take Support", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "complimentSwarmYou": {
        "emotionsToAdd": {
            "complimentSmall": 3
        }, 
        "name": "Compliment", 
        "image": "tower_memoryRing", 
        "key": "complimentSwarmYou", 
        "memoryKey": "memory_complimentSwarmYou", 
        "emotionTags": [
            "joy", 
            "self"
        ], 
        "resourceKey": "complimentSwarmYouMineConstruction", 
        "activeImage": "tower_memoryRing_activeOutline-0099ff"
    }, 
    "noSupportMenu": {
        "image": "goal_goalDisavowal-000000", 
        "name": "COMPLETED - Give Him No Support", 
        "key": "noSupportMenu"
    }, 
    "anxietyMineConstruction": {
        "key": "anxietyMineConstruction", 
        "constructionIdentifier": "anxietyMine", 
        "name": "Constructing - Anxiety", 
        "image": "trait-aaaaaa99_tower_mineCaution", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Anxiety", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "spendTimeCleverButton": {
        "constructionKey": "spendTimeCleverGoalConstruction", 
        "name": "Spend Time", 
        "image": "goal_mineCheer-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "spendTimeCleverGoal", 
        "key": "spendTimeCleverButton", 
        "description": "Requires will."
    }, 
    "relationshipMineConstruction": {
        "key": "relationshipMineConstruction", 
        "constructionIdentifier": "relationshipMine", 
        "name": "Constructing - Time Together", 
        "image": "trait-aaaaaa99_tower_towerDate", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Time Together", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "makeWorkWinMajorGoal": {
        "key": "makeWorkWinMajorGoal", 
        "randomPosition": 0, 
        "name": "Talk About Work Success", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "major": 1, 
            "workWin": 1
        }, 
        "entitiesToMake": "workWinMajor", 
        "goalMenuKey": "makeWorkWinMajorMenu"
    }, 
    "needWorkGoal": {
        "key": "needWorkGoal", 
        "randomPosition": 1, 
        "name": "Need To Do Good Work", 
        "makeOnTimeOut": "slowWorkFlat", 
        "image": "goal_drive-000000", 
        "sourceTrait": "him", 
        "currencyRequested": {
            "goodWork": 3
        }, 
        "goalMenuKey": "needWorkMenu", 
        "timeToDeath": 150
    }, 
    "cleverResponseMenu": {
        "image": "goal_towerFlirt-000000", 
        "name": "COMPLETED - Clever Response", 
        "key": "cleverResponseMenu"
    }, 
    "flashback_aloneMed": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_aloneMed", 
        "emotionTags": "aloneMed", 
        "resourceKeys": [
            "aloneMed"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes aloneMed"
    }, 
    "supportTowerConstruction": {
        "key": "supportTowerConstruction", 
        "constructionIdentifier": "supportTower", 
        "name": "Constructing - Support", 
        "image": "trait-aaaaaa99_tower_dependence", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Support", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "himEntities": {
        "entitiesToMake": [
            "selfValuePlaced", 
            "calmnessTowerPlaced", 
            "toughTowerPlaced", 
            "callousnessTowerPlaced"
        ], 
        "key": "himEntities"
    }, 
    "hisEmotion": {
        "name": "his emotion", 
        "key": "hisEmotion", 
        "tags": [
            "hisEmotion"
        ]
    }, 
    "learnHimGoal": {
        "key": "learnHimGoal", 
        "randomPosition": 0, 
        "name": "Learn About Him", 
        "image": "goal_book-000000", 
        "currencyRequested": {
            "social": 3
        }, 
        "entitiesToMake": "learnHimResult", 
        "goalMenuKey": "learnHimMenu"
    }, 
    "aloneFlatHim": {
        "resourceCount": 1, 
        "name": "Feeling Alone", 
        "image": "tower_eyeTear", 
        "destination": "himself", 
        "key": "aloneFlatHim", 
        "emotionTags": [
            "sadness"
        ], 
        "resourceKeys": "aloneMed", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "joyBurst": {
        "emotionsToAdd": {
            "joy": 1
        }, 
        "name": "Joy", 
        "image": "tower_mineCheer", 
        "key": "joyBurst", 
        "memoryKey": "memory_joyBurst", 
        "emotionTags": "self", 
        "resourceKey": "joyBurstMineConstruction", 
        "activeImage": "tower_mineCheer_activeOutline-0099ff"
    }, 
    "makeWorkWinMajorMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Talk About Work Success", 
        "key": "makeWorkWinMajorMenu"
    }, 
    "exploreNewGoal": {
        "key": "exploreNewGoal", 
        "randomPosition": 1, 
        "name": "Explore New Thing", 
        "image": "goal_spark-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": "exploreNewResult", 
        "goalMenuKey": "exploreNewMenu", 
        "description": "Is this the one?"
    }, 
    "memory_casualSwarmYou": {
        "image": "trait-aa1717", 
        "memoryEmotions": [
            "anger"
        ], 
        "key": "memory_casualSwarmYou", 
        "name": "Casual Cruelty"
    }, 
    "findUsefulMenu": {
        "image": "goal_spark-000000", 
        "completeText": "That's something you can try.", 
        "name": "COMPLETED - Find Useful Thing To Do", 
        "key": "findUsefulMenu"
    }, 
    "stupidDeposit": {
        "randomPosition": 1, 
        "timeToDeath": 120, 
        "image": "tower_towerThinkAbout", 
        "sourceTrait": "hisWork", 
        "deposit": {
            "stupid": 3
        }, 
        "key": "stupidDeposit", 
        "activeImage": "tower_towerThinkAbout_activeOutline-0099ff", 
        "name": "Stupidity"
    }, 
    "killDefineRoleButton": {
        "entitiesToKill": [
            "defineRoleButton"
        ], 
        "key": "killDefineRoleButton"
    }, 
    "oldHurtMineConstruction": {
        "key": "oldHurtMineConstruction", 
        "constructionIdentifier": "oldHurtMine", 
        "name": "Old Pain", 
        "image": "tower_eyeTear-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Old Pain"
    }, 
    "pushInsecurityGoalConstruction": {
        "key": "pushInsecurityGoalConstruction", 
        "constructionIdentifier": "pushInsecurityGoal", 
        "name": "Constructing - Push Insecurity", 
        "image": "trait-aaaaaa99_goal_drive-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Push Insecurity", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "willMineButton": {
        "constructionKey": "willMineConstruction", 
        "name": "Drive", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_mineWill", 
        "currenciesMade": [
            "will"
        ], 
        "entityKey": "willMine", 
        "limitingKeys": [
            "willMine", 
            "willMineConstruction"
        ], 
        "key": "willMineButton", 
        "description": "makes will"
    }, 
    "mistrustJoyTower": {
        "description": "Uses insecurity to calm joy", 
        "charges": 3, 
        "image": "tower_mineCheer", 
        "damage": 60, 
        "damageMultipliers": {
            "joy": 1
        }, 
        "impulseTicks": 3, 
        "key": "mistrustJoyTower", 
        "activeImage": "tower_mineCheer_activeOutline-0099ff", 
        "name": "Mistrust of Joy"
    }, 
    "spendTimeWarmGoal": {
        "key": "spendTimeWarmGoal", 
        "randomPosition": 0, 
        "name": "Spend Time", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "goalMenuKey": "spendTimeWarmMenu"
    }, 
    "hisWorkToHisBadWork": {
        "sourceTrait": "hisWork", 
        "newTrait": "hisBadWork", 
        "key": "hisWorkToHisBadWork"
    }, 
    "gainControlMenu": {
        "y": 164, 
        "x": 237
    }, 
    "killWork": {
        "entitiesToKill": [
            "faithCrisis", 
            "hisWork"
        ], 
        "key": "killWork"
    }, 
    "flashback_guiltMed": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_guiltMed", 
        "emotionTags": "guiltMed", 
        "resourceKeys": [
            "guiltMed"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes guiltMed"
    }, 
    "takeSupportButton": {
        "constructionKey": "takeSupportTowerConstruction", 
        "maxTowerCount": 1, 
        "name": "Take Support", 
        "image": "tower_dependence", 
        "entityCost": {
            "support": 5
        }, 
        "entityKey": "takeSupportTower", 
        "limitingKeys": [
            "takeSupportTower", 
            "takeSupportTowerConstruction"
        ], 
        "key": "takeSupportButton", 
        "subPanel": "Defenses", 
        "description": "Uses support to calm anger, sadness"
    }, 
    "switchCalmnessDeposit": {
        "entitiesToMake": "calmnessDeposit", 
        "key": "switchCalmnessDeposit"
    }, 
    "exploreNewMenu": {
        "image": "goal_spark-000000", 
        "name": "COMPLETED - Explore New Thing", 
        "key": "exploreNewMenu"
    }, 
    "insecureMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Handle Insecurity", 
        "key": "insecureMenu"
    }, 
    "busyWorkTower": {
        "description": [
            "I'm never able to focus on work when I'm feeling happy", 
            "Uses busy work to calm anger, sadness"
        ], 
        "charges": 3, 
        "image": "tower_drive", 
        "damage": 60, 
        "damageMultipliers": {
            "anger": 1, 
            "sadness": 1
        }, 
        "impulseTicks": 3, 
        "key": "busyWorkTower", 
        "activeImage": "tower_drive_activeOutline-0099ff", 
        "name": "Keeping Busy"
    }, 
    "findUsefulResult": {
        "goodEntities": {
            "doUsefulGoal": 2
        }, 
        "badEntities": "explainFindUsefulFail", 
        "key": "findUsefulResult"
    }, 
    "oldLifeMine": {
        "resourceCount": 1, 
        "name": "Reminder Of Your Old Life", 
        "image": "tower_eyeTear", 
        "key": "oldLifeMine", 
        "emotionTags": [
            "sadness", 
            "self", 
            "oldFailMed"
        ], 
        "resourceKeys": [
            "oldFailMed"
        ], 
        "activeImage": "tower_eyeTear_activeOutline-0099ff", 
        "description": "makes oldFailMed"
    }, 
    "startConverseGoalConstruction": {
        "key": "startConverseGoalConstruction", 
        "constructionIdentifier": "startConverseGoal", 
        "name": "Constructing - Start Conversation", 
        "image": "trait-aaaaaa99_goal_goalConvinceWife-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Start Conversation", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "thought": {
        "name": "thought", 
        "key": "thought", 
        "tags": [
            "thought"
        ]
    }, 
    "person": {
        "focusPanelKey": "focusPanel2", 
        "playerKillable": "true"
    }, 
    "cheer": {
        "name": "cheer", 
        "key": "cheer", 
        "tags": [
            "cheer"
        ]
    }, 
    "flipMature": {
        "trait2": "fun", 
        "trait1": "mature", 
        "key": "flipMature"
    }, 
    "criticismButton": {
        "constructionKey": "criticismTowerConstruction", 
        "name": "Criticize", 
        "image": "tower_mineFrustration", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "criticismTower", 
        "limitingKeys": [
            "criticismTower", 
            "criticismTowerConstruction"
        ], 
        "key": "criticismButton", 
        "subPanel": "Towers", 
        "description": "Converts completeWork + cruelty -> criticism"
    }, 
    "needPainTower": {
        "image": "tower_droop", 
        "activeImage": "tower_droop_activeOutline-0099ff", 
        "name": "Need Help", 
        "key": "needPainTower", 
        "description": "Converts pain -> need"
    }, 
    "openUpButton": {
        "constructionKey": "openUpGoalConstruction", 
        "name": "Open Up", 
        "image": "goal_goalConvinceWife-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "openUpGoal", 
        "key": "openUpButton", 
        "description": "Requires will."
    }, 
    "strengthMineButton": {
        "constructionKey": "strengthMineConstruction", 
        "name": "Strength", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_weight", 
        "currenciesMade": [
            "strength"
        ], 
        "entityKey": "strengthMine", 
        "limitingKeys": [
            "strengthMine", 
            "strengthMineConstruction"
        ], 
        "key": "strengthMineButton", 
        "description": "makes strength"
    }, 
    "toughTowerPlaced": {
        "y": 23, 
        "x": 13, 
        "tower": "toughTower", 
        "key": "toughTowerPlaced"
    }, 
    "flirtTowerConstruction": {
        "key": "flirtTowerConstruction", 
        "constructionIdentifier": "flirtTower", 
        "name": "Constructing - Flirtation", 
        "image": "trait-aaaaaa99_tower_towerFlirt", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Flirtation", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "toughButton": {
        "constructionKey": "toughTowerConstruction", 
        "name": "Toughness", 
        "image": "tower_energy", 
        "entityCost": {
            "strength": 3
        }, 
        "entityKey": "toughTower", 
        "limitingKeys": [
            "toughTower", 
            "toughTowerConstruction"
        ], 
        "key": "toughButton", 
        "subPanel": "Defenses", 
        "description": "Uses strength to calm anger, joy, sadness"
    }, 
    "needPainAction": {
        "currenciesRequired": [
            "pain"
        ], 
        "towerKey": "needPainTower", 
        "currenciesToMake": [
            "need"
        ], 
        "name": "Need Help", 
        "key": "needPainAction"
    }, 
    "speakOfValueGoalConstruction": {
        "key": "speakOfValueGoalConstruction", 
        "constructionIdentifier": "speakOfValueGoal", 
        "name": "Constructing - Speak of Your Value", 
        "image": "trait-aaaaaa99_goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Speak of Your Value", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "mistrustJoyPlaced": {
        "y": 23, 
        "x": 13, 
        "tower": "mistrustJoyTower", 
        "key": "mistrustJoyPlaced"
    }, 
    "pushInsecurityGoal": {
        "key": "pushInsecurityGoal", 
        "randomPosition": 0, 
        "name": "Push Insecurity", 
        "image": "goal_drive-000000", 
        "currencyRequested": {
            "insecure": 3, 
            "social": 3
        }, 
        "entitiesToMake": {
            "insecureSwarmHim": 100, 
            "calmnessDeposit": 100, 
            "switchYouInfoDeposit": 50
        }, 
        "interactionKeys": [
            "self"
        ], 
        "goalMenuKey": "pushInsecurityMenu", 
        "description": "How does this never resonate with him. What's wrong with him?"
    }, 
    "calmnessMineButton": {
        "constructionKey": "calmnessMineConstruction", 
        "name": "Calmness", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_wave", 
        "currenciesMade": [
            "calm"
        ], 
        "entityKey": "calmnessMine", 
        "limitingKeys": [
            "calmnessMine", 
            "calmnessMineConstruction"
        ], 
        "key": "calmnessMineButton", 
        "description": "makes calm"
    }, 
    "rejectMeanlessMenu": {
        "image": "goal_openMind-000000", 
        "name": "COMPLETED - Reject Meaninglessness", 
        "key": "rejectMeanlessMenu"
    }, 
    "pushTowerConstruction": {
        "key": "pushTowerConstruction", 
        "constructionIdentifier": "pushTower", 
        "name": "Constructing - Push At Him", 
        "image": "trait-aaaaaa99_tower_newNote", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Push At Him", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "workTopicDeposit": {
        "timeToDeath": 120, 
        "image": "tower_puzzle", 
        "deposit": {
            "workTopic": 3
        }, 
        "key": "workTopicDeposit", 
        "activeImage": "tower_puzzle_activeOutline-0099ff", 
        "name": "Work Topic"
    }, 
    "socialTowerConstruction": {
        "key": "socialTowerConstruction", 
        "constructionIdentifier": "socialTower", 
        "name": "Constructing - Social", 
        "image": "trait-aaaaaa99_tower_mineSocial", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Social", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "supportCrisisGoalConstruction": {
        "key": "supportCrisisGoalConstruction", 
        "constructionIdentifier": "supportCrisisGoal", 
        "name": "Constructing - Support Partner", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Support Partner", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "supportAction": {
        "currenciesRequired": [
            "cheer"
        ], 
        "towerKey": "supportTower", 
        "currenciesToMake": [
            "support"
        ], 
        "name": "Support", 
        "key": "supportAction"
    }, 
    "callousnessButton": {
        "constructionKey": "callousnessTowerConstruction", 
        "maxTowerCount": 1, 
        "name": "Callousness", 
        "image": "tower_numb", 
        "entityCost": {
            "selfishness": 5
        }, 
        "entityKey": "callousnessTower", 
        "limitingKeys": [
            "callousnessTower", 
            "callousnessTowerConstruction"
        ], 
        "key": "callousnessButton", 
        "subPanel": "Defenses", 
        "description": "Uses selfishness to calm anger, joy, sadness"
    }, 
    "makeStupidityFlatMenu": {
        "image": "goal_mineFrustration-000000", 
        "name": "COMPLETED - Make Statement About Stupidity", 
        "key": "makeStupidityFlatMenu"
    }, 
    "criticizeSelfButton": {
        "constructionKey": "criticizeSelfGoalConstruction", 
        "name": "Criticize Yourself", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "criticizeSelfGoal", 
        "key": "criticizeSelfButton", 
        "description": "Requires will."
    }, 
    "flipHurt": {
        "trait2": "strong", 
        "trait1": "hurting", 
        "key": "flipHurt"
    }, 
    "setHimRelation": {
        "flag": "himRelation", 
        "key": "setHimRelation"
    }, 
    "him_ext": {
        "personHeld": "him", 
        "image": [
            "trait-993399", 
            "trait-892D89", 
            "trait-A838A8"
        ], 
        "name": "Him", 
        "key": "him_ext", 
        "sourceKey": "him"
    }, 
    "getFeedbackMenu": {
        "image": "goal_hook-000000", 
        "name": "COMPLETED - Get Feedback", 
        "key": "getFeedbackMenu"
    }, 
    "spendTimeWarmGoalConstruction": {
        "key": "spendTimeWarmGoalConstruction", 
        "constructionIdentifier": "spendTimeWarmGoal", 
        "name": "Constructing - Spend Time", 
        "image": "trait-aaaaaa99_goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Spend Time", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "oldHurtMine": {
        "resourceCount": 3, 
        "name": "Old Pain", 
        "image": "tower_eyeTear", 
        "key": "oldHurtMine", 
        "emotionTags": [
            "sadness", 
            "self", 
            "oldFailSmall"
        ], 
        "resourceKeys": [
            "oldFailSmall"
        ], 
        "activeImage": "tower_eyeTear_activeOutline-0099ff", 
        "description": "makes oldFailSmall"
    }, 
    "calmPartnerGoalConstruction": {
        "key": "calmPartnerGoalConstruction", 
        "constructionIdentifier": "calmPartnerGoal", 
        "name": "Constructing - Calm Partner", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Calm Partner", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "cleverResponseGoal": {
        "key": "cleverResponseGoal", 
        "randomPosition": 1, 
        "name": "Clever Response", 
        "image": "goal_towerFlirt-000000", 
        "currencyRequested": {
            "insecure": 1
        }, 
        "entitiesToMake": "youInfoDeposit", 
        "goalMenuKey": "cleverResponseMenu", 
        "timeToDeath": 60
    }, 
    "gameStartMenu": {
        "completeText": [
            "You've just started a new relationship and that's fun, but are you", 
            "going to change with it? Is he?"
        ], 
        "name": "START!", 
        "key": "gameStartMenu", 
        "height": 675
    }, 
    "selfEsteemDeposit": {
        "image": "tower_trophy", 
        "activeImage": "tower_trophy_activeOutline-0099ff", 
        "name": "Self Esteem", 
        "key": "selfEsteemDeposit", 
        "deposit": {
            "selfEsteem": 3
        }
    }, 
    "flashback_complimentSmall": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_complimentSmall", 
        "emotionTags": "complimentSmall", 
        "resourceKeys": [
            "complimentSmall"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes complimentSmall"
    }, 
    "spendTimeResult": {
        "goodEntities": [
            "goodSpendTimeResult", 
            "goodSpendTimeResult"
        ], 
        "badEntities": "explainSpendTimeFail", 
        "key": "spendTimeResult"
    }, 
    "clickText": {
        "touchable": "true", 
        "timeToDeath": 30, 
        "key": "clickText"
    }, 
    "sharePainGoal": {
        "key": "sharePainGoal", 
        "randomPosition": 0, 
        "name": "Share Pain", 
        "image": "goal_minePain-000000", 
        "currencyRequested": {
            "pain": 3, 
            "social": 3
        }, 
        "entitiesToMake": "sharePainResult", 
        "goalMenuKey": "sharePainMenu"
    }, 
    "joyMap": {
        "startManagedEntities": [
            "cheerMine"
        ], 
        "emotionToMap": "joy", 
        "emotionMappedEntities": [
            "supportButton", 
            "rechargeButton"
        ], 
        "key": "joyMap"
    }, 
    "obsessionsButton": {
        "constructionKey": "obsessionsTowerConstruction", 
        "maxTowerCount": 1, 
        "name": "Obsessions", 
        "image": "tower_daydream", 
        "entityCost": {
            "obsession": 3
        }, 
        "entityKey": "obsessionsTower", 
        "limitingKeys": [
            "obsessionsTower", 
            "obsessionsTowerConstruction"
        ], 
        "key": "obsessionsButton", 
        "subPanel": "Defenses", 
        "description": "Uses obsession to calm anger, joy, sadness"
    }, 
    "criticismSwarm": {
        "resourceCount": 3, 
        "name": "Criticism", 
        "image": "tower_eyeTear", 
        "destination": "himself", 
        "key": "criticismSwarm", 
        "emotionTags": [
            "sadness"
        ], 
        "resourceKeys": "criticismSmall", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "acceptConnectionYouMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Accept Connection", 
        "key": "acceptConnectionYouMenu"
    }, 
    "appreciateWorkButton": {
        "constructionKey": "appreciateWorkGoalConstruction", 
        "name": "Appreciate His Work", 
        "image": "goal_towerFlirt-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "appreciateWorkGoal", 
        "key": "appreciateWorkButton", 
        "description": "Requires work topic, social."
    }, 
    "beBelievedInGoal": {
        "key": "beBelievedInGoal", 
        "randomPosition": 1, 
        "name": "Be Believed In", 
        "image": "goal_trophy-000000", 
        "currencyRequested": {
            "support": 3
        }, 
        "entitiesToMake": "selfEsteemDeposit", 
        "interactionKeys": [
            "himself"
        ], 
        "goalMenuKey": "beBelievedInMenu", 
        "timeToDeath": 120
    }, 
    "relationshipPathGood": {
        "startKey": "relationship", 
        "endKey": "good", 
        "key": "relationshipPathGood"
    }, 
    "casualSwarmYouMine": {
        "resourceCount": 3, 
        "name": "Casual Cruelty", 
        "image": "tower_mineCaution", 
        "key": "casualSwarmYouMine", 
        "emotionTags": [
            "anger", 
            "self", 
            "casualSmall"
        ], 
        "resourceKeys": [
            "casualSmall"
        ], 
        "activeImage": "tower_mineCaution_activeOutline-0099ff", 
        "description": "makes casualSmall"
    }, 
    "goodPathClever": {
        "startKey": "good", 
        "endKey": "clever", 
        "key": "goodPathClever"
    }, 
    "flipGood": {
        "trait2": "selfish", 
        "trait1": "good", 
        "key": "flipGood"
    }, 
    "insecureGoal": {
        "key": "insecureGoal", 
        "randomPosition": 1, 
        "name": "Handle Insecurity", 
        "makeOnTimeOut": "insecureSwarmYou", 
        "image": "goal_eyeTear-000000", 
        "sourceTrait": "insecurity", 
        "currencyRequested": {
            "value": 3
        }, 
        "goalMenuKey": "insecureMenu", 
        "timeToDeath": 150
    }, 
    "memory_sadAttack": {
        "image": "trait-013d70", 
        "memoryEmotions": [
            "sadness"
        ], 
        "key": "memory_sadAttack", 
        "name": "Sadness Burst"
    }, 
    "sharePainMenu": {
        "image": "goal_minePain-000000", 
        "name": "COMPLETED - Share Pain", 
        "key": "sharePainMenu"
    }, 
    "complimentSwarm": {
        "resourceCount": 3, 
        "name": "Compliment", 
        "image": "tower_memoryRing", 
        "destination": "himself", 
        "key": "complimentSwarm", 
        "emotionTags": [
            "joy"
        ], 
        "resourceKeys": "complimentSmall", 
        "activeImage": "tower_memoryRing_activeOutline-0099ff"
    }, 
    "helpful": {
        "name": "Helpful", 
        "image": "trait-887788", 
        "personHeld": "you", 
        "isaacEntities": [
            "helpValueButton", 
            "findHelpButton", 
            "feelUselessButton", 
            "obsessHimButton", 
            "winButton"
        ], 
        "key": "helpful", 
        "interactionKeys": [
            "self"
        ]
    }, 
    "helpDeposit": {
        "image": "tower_dependence", 
        "activeImage": "tower_dependence_activeOutline-0099ff", 
        "name": "Helped", 
        "key": "helpDeposit", 
        "deposit": {
            "helpHim": 3
        }
    }, 
    "trySomethingGoal": {
        "key": "trySomethingGoal", 
        "randomPosition": 0, 
        "name": "Try Something New", 
        "image": "goal_trophy-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": {
            "restlessToHisWork": 50
        }, 
        "goalMenuKey": "trySomethingMenu"
    }, 
    "thinkMineConstruction": {
        "key": "thinkMineConstruction", 
        "constructionIdentifier": "thinkMine", 
        "name": "Constructing - Think About Helping", 
        "image": "trait-aaaaaa99_tower_mineThought", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Think About Helping", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "askAboutRestlessButton": {
        "constructionKey": "askAboutRestlessGoalConstruction", 
        "name": "Ask About Restlessness", 
        "image": "goal_goalAskAbout-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "askAboutRestlessGoal", 
        "key": "askAboutRestlessButton", 
        "interactionKeys": [
            "self"
        ], 
        "description": [
            "Requires social.", 
            "Makes Info on Partner."
        ]
    }, 
    "probeTopicGoal": {
        "key": "probeTopicGoal", 
        "randomPosition": 1, 
        "name": "Probe Topic", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "push": 3, 
            "topic": 3
        }, 
        "entitiesToMake": "probedProblemDeposit", 
        "goalMenuKey": "probeTopicMenu"
    }, 
    "learnHimButton": {
        "constructionKey": "learnHimGoalConstruction", 
        "name": "Learn About Him", 
        "image": "goal_book-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "learnHimGoal", 
        "key": "learnHimButton", 
        "interactionKeys": [
            "self"
        ], 
        "description": "Requires social."
    }, 
    "flashback_insecureSmallConstruction": {
        "key": "flashback_insecureSmallConstruction", 
        "constructionIdentifier": "flashback_insecureSmall", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "defineHelpMenu": {
        "image": "goal_heart-000000", 
        "name": "COMPLETED - Define Yourself as Helpful", 
        "key": "defineHelpMenu"
    }, 
    "jealousyBurstMineConstruction": {
        "key": "jealousyBurstMineConstruction", 
        "constructionIdentifier": "jealousyBurstMine", 
        "name": "Jealousy", 
        "image": "tower_depositSin-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Jealousy"
    }, 
    "whatsNewMenu": {
        "image": "goal_spark-000000", 
        "name": "COMPLETED - What Have You Tried?", 
        "key": "whatsNewMenu"
    }, 
    "casualEmo": {
        "youKeys": "casualSwarmYou", 
        "key": "casualEmo", 
        "himKeys": "casualMedHim"
    }, 
    "killStartRelationYouButton": {
        "entitiesToKill": [
            "startRelationYouButton"
        ], 
        "key": "killStartRelationYouButton"
    }, 
    "findLifeHelpGoal": {
        "key": "findLifeHelpGoal", 
        "randomPosition": 1, 
        "name": "Find Way To Help From Your Life", 
        "image": "goal_insecure-000000", 
        "currencyRequested": {
            "insecurity": 3
        }, 
        "entitiesToMake": "findLifeHelpResult", 
        "goalMenuKey": "findLifeHelpMenu"
    }, 
    "mistrustJoyButton": {
        "constructionKey": "mistrustJoyTowerConstruction", 
        "maxTowerCount": 1, 
        "name": "Mistrust of Joy", 
        "image": "tower_mineCheer", 
        "entityCost": {
            "insecure": 3
        }, 
        "entityKey": "mistrustJoyTower", 
        "limitingKeys": [
            "mistrustJoyTower", 
            "mistrustJoyTowerConstruction"
        ], 
        "key": "mistrustJoyButton", 
        "subPanel": "Defenses", 
        "description": "Uses insecurity to calm joy"
    }, 
    "selfishPathRelationship": {
        "startKey": "selfish", 
        "endKey": "relationship", 
        "key": "selfishPathRelationship"
    }, 
    "slowWorkMed": {
        "emotion": "anger", 
        "name": "slow work", 
        "image": "creepLarge-ff0000", 
        "memoryImage": "memoryAnger", 
        "health": 60, 
        "key": "slowWorkMed"
    }, 
    "selfishness": {
        "name": "selfishness", 
        "key": "selfishness", 
        "tags": [
            "selfishness"
        ]
    }, 
    "switchFeedCrisisButton": {
        "entitiesToMake": "feedCrisisButton", 
        "key": "switchFeedCrisisButton"
    }, 
    "flashback_oldFailSmallConstruction": {
        "key": "flashback_oldFailSmallConstruction", 
        "constructionIdentifier": "flashback_oldFailSmall", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "indulgeViceButton": {
        "constructionKey": "indulgeViceGoalConstruction", 
        "name": "Indulge Vice", 
        "image": "goal_mineCheer-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "indulgeViceGoal", 
        "key": "indulgeViceButton", 
        "description": "Requires will."
    }, 
    "creep": {
        "planeOfExistence": "path"
    }, 
    "reachOutBranch": {
        "flagToCheck": "reachOutDone", 
        "key": "reachOutBranch", 
        "notFlagEntities": "reachOutButton"
    }, 
    "oldLife": {
        "emotionsToAdd": {
            "oldFailMed": 1
        }, 
        "name": "Reminder Of Your Old Life", 
        "image": "tower_eyeTear", 
        "key": "oldLife", 
        "memoryKey": "memory_oldLife", 
        "emotionTags": [
            "sadness", 
            "self"
        ], 
        "resourceKey": "oldLifeMineConstruction", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "feedCrisisGoalConstruction": {
        "key": "feedCrisisGoalConstruction", 
        "constructionIdentifier": "feedCrisisGoal", 
        "name": "Constructing - Feed Crisis", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Feed Crisis", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "tryForConnectionHimMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Try For Connection", 
        "key": "tryForConnectionHimMenu"
    }, 
    "selfish_ext": {
        "personHeld": "good", 
        "image": [
            "trait-663333", 
            "trait-5B2D2D", 
            "trait-703838"
        ], 
        "name": "Selfish", 
        "key": "selfish_ext", 
        "sourceKey": "selfish"
    }, 
    "needBusyButton": {
        "constructionKey": "needBusyTowerConstruction", 
        "name": "Need Help", 
        "image": "tower_droop", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "needBusyTower", 
        "limitingKeys": [
            "needBusyTower", 
            "needBusyTowerConstruction"
        ], 
        "key": "needBusyButton", 
        "subPanel": "Towers", 
        "interactionKeys": [
            "himself"
        ], 
        "description": "Converts busy work -> need"
    }, 
    "makeWorkWinMajorGoalConstruction": {
        "key": "makeWorkWinMajorGoalConstruction", 
        "constructionIdentifier": "makeWorkWinMajorGoal", 
        "name": "Constructing - Talk About Work Success", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Talk About Work Success", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "exploreStrengthGoalConstruction": {
        "key": "exploreStrengthGoalConstruction", 
        "constructionIdentifier": "exploreStrengthGoal", 
        "name": "Constructing - Explore His Strength", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Explore His Strength", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "switchYouInfoDeposit": {
        "entitiesToMake": "youInfoDeposit", 
        "key": "switchYouInfoDeposit"
    }, 
    "flashback_insecureSmall": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_insecureSmall", 
        "emotionTags": "insecureSmall", 
        "resourceKeys": [
            "insecureSmall"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes insecureSmall"
    }, 
    "critical": {
        "name": "Critical", 
        "aliveEntities": {
            "quietCriticismGoal": 5
        }, 
        "image": "trait-ff0066", 
        "personHeld": "you", 
        "isaacEntities": [
            "makeCriticismSwarmButton", 
            "makeCriticismFlatButton", 
            "criticizeSelfButton"
        ], 
        "key": "critical", 
        "interactionKeys": [
            "self"
        ]
    }, 
    "deriveWorkTopicGoalConstruction": {
        "key": "deriveWorkTopicGoalConstruction", 
        "constructionIdentifier": "deriveWorkTopicGoal", 
        "name": "Constructing - Derive Work Points", 
        "image": "trait-aaaaaa99_goal_towerThinkAbout-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Derive Work Points", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "hardWorkMenu": {
        "image": "goal_weight-000000", 
        "name": "COMPLETED - Hard Work", 
        "key": "hardWorkMenu"
    }, 
    "beSupportedMenu": {
        "image": "goal_dependence-000000", 
        "name": "COMPLETED - Take Support", 
        "key": "beSupportedMenu"
    }, 
    "makeDreamDeathMajorGoal": {
        "key": "makeDreamDeathMajorGoal", 
        "randomPosition": 0, 
        "name": "Talk About Death of Dream", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "major": 1, 
            "dreamDeath": 1
        }, 
        "entitiesToMake": "dreamDeathMajor", 
        "goalMenuKey": "makeDreamDeathMajorMenu"
    }, 
    "socialWarmMine": {
        "image": "tower_mineSocial", 
        "resourceKeys": [
            "social_warm"
        ], 
        "name": "Social", 
        "key": "socialWarmMine", 
        "activeImage": "tower_mineSocial_activeOutline-0099ff"
    }, 
    "cheerMine": {
        "image": "tower_mineCheer", 
        "resourceKeys": [
            "cheer"
        ], 
        "name": "Cheer Mine", 
        "key": "cheerMine", 
        "activeImage": "tower_mineCheer_activeOutline-0099ff"
    }, 
    "difficultySetting": {
        "key": "difficultySetting"
    }, 
    "friendMeditateTowerConstruction": {
        "key": "friendMeditateTowerConstruction", 
        "constructionIdentifier": "friendMeditateTower", 
        "name": "Constructing - Be Calmed Down", 
        "image": "trait-aaaaaa99_tower_goalCalmDown-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Be Calmed Down", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "explainFeedCrisisFail": {
        "completeText": "Your words had impact, but he found a way past them anyway.", 
        "key": "explainFeedCrisisFail"
    }, 
    "oldFailSwarm": {
        "resourceCount": 3, 
        "name": "Old Failures", 
        "image": "tower_eyeTear", 
        "destination": "himself", 
        "key": "oldFailSwarm", 
        "emotionTags": [
            "sadness"
        ], 
        "resourceKeys": "oldFailSmall", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "flashback_criticismSmallConstruction": {
        "key": "flashback_criticismSmallConstruction", 
        "constructionIdentifier": "flashback_criticismSmall", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "gainControl_anger": {
        "barColor": "cc9999", 
        "text": "You're just too angry to think right now.", 
        "textColor": 660000, 
        "key": "gainControl_anger"
    }, 
    "obsessGoal": {
        "key": "obsessGoal", 
        "randomPosition": 0, 
        "name": "Obsess", 
        "image": "goal_motivation-000000", 
        "currencyRequested": {
            "envy": 3, 
            "insecure": 3
        }, 
        "entitiesToMake": "obsessionDeposit", 
        "goalMenuKey": "obsessMenu"
    }, 
    "askHelpGoal": {
        "key": "askHelpGoal", 
        "randomPosition": 0, 
        "name": "Ask For Help", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "social": 3
        }, 
        "entitiesToMake": "switchHelpGoal", 
        "goalMenuKey": "askHelpMenu"
    }, 
    "you_ext": {
        "personHeld": "you", 
        "image": [
            "trait-99ff66", 
            "trait-89E55B", 
            "trait-A8FF70"
        ], 
        "name": "You", 
        "key": "you_ext", 
        "sourceKey": "you"
    }, 
    "joyBurstMineConstruction": {
        "key": "joyBurstMineConstruction", 
        "constructionIdentifier": "joyBurstMine", 
        "name": "Joy", 
        "image": "tower_mineCheer-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Joy"
    }, 
    "needBusyAction": {
        "currenciesRequired": [
            "busyWork"
        ], 
        "towerKey": "needBusyTower", 
        "currenciesToMake": [
            "need"
        ], 
        "name": "Need Help", 
        "key": "needBusyAction"
    }, 
    "complimentYouGoalConstruction": {
        "key": "complimentYouGoalConstruction", 
        "constructionIdentifier": "complimentYouGoal", 
        "name": "Constructing - Compliment You", 
        "image": "trait-aaaaaa99_goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Compliment You", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "feedCrisisButton": {
        "constructionKey": "feedCrisisGoalConstruction", 
        "name": "Feed Crisis", 
        "image": "goal_eyeTear-000000", 
        "description": "Requires cruelty.", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "feedCrisisGoal", 
        "key": "feedCrisisButton", 
        "interactionKeys": [
            "self"
        ], 
        "displayRiskIcon": 1
    }, 
    "flirtationMineConstruction": {
        "key": "flirtationMineConstruction", 
        "constructionIdentifier": "flirtationMine", 
        "name": "Constructing - Flirtation", 
        "image": "trait-aaaaaa99_tower_towerFlirt", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Flirtation", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "completeWorkDeposit": {
        "randomPosition": 1, 
        "timeToDeath": 120, 
        "image": "tower_towerThinkAbout", 
        "sourceTrait": "hisWork", 
        "deposit": {
            "completeWork": 3
        }, 
        "key": "completeWorkDeposit", 
        "activeImage": "tower_towerThinkAbout_activeOutline-0099ff", 
        "name": "Complete Work"
    }, 
    "aloneSmall": {
        "emotion": "sadness", 
        "name": "feeling alone", 
        "image": "creep-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 20, 
        "key": "aloneSmall"
    }, 
    "goodnessMineConstruction": {
        "key": "goodnessMineConstruction", 
        "constructionIdentifier": "goodnessMine", 
        "name": "Constructing - Goodness", 
        "image": "trait-aaaaaa99_tower_newNote", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Goodness", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "killCapable": {
        "entitiesToKill": [
            "capable"
        ], 
        "key": "killCapable"
    }, 
    "restLife": {
        "sector": [
            0, 
            3
        ], 
        "name": "Rest of Your Life", 
        "aliveEntities": {
            "oldLife": 5, 
            "choreGoal": 5
        }, 
        "startManagedEntities": [
            "choreGoal"
        ], 
        "personHeld": "you", 
        "key": "restLife", 
        "interactionKeys": [
            "self"
        ], 
        "maxLevel": 3, 
        "image": "trait-66cc66"
    }, 
    "forceOpennessGoal": {
        "key": "forceOpennessGoal", 
        "randomPosition": 0, 
        "name": "Force Some Openness", 
        "image": "goal_weight-000000", 
        "currencyRequested": {
            "will": 6
        }, 
        "entitiesToMake": "opennessDeposit", 
        "goalMenuKey": "forceOpennessMenu", 
        "timeToDeath": 150
    }, 
    "insecurityPathNewRelationship": {
        "startKey": "insecurity", 
        "endKey": "newRelationship", 
        "key": "insecurityPathNewRelationship"
    }, 
    "insecureSwarmYou": {
        "emotionsToAdd": {
            "insecureSmall": 3
        }, 
        "name": "Insecurities", 
        "image": "tower_eyeTear", 
        "key": "insecureSwarmYou", 
        "memoryKey": "memory_insecureSwarmYou", 
        "emotionTags": [
            "sadness", 
            "self"
        ], 
        "resourceKey": "insecureSwarmYouMineConstruction", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "findUsefulGoal": {
        "key": "findUsefulGoal", 
        "randomPosition": 0, 
        "name": "Find Useful Thing To Do", 
        "image": "goal_spark-000000", 
        "currencyRequested": {
            "thought": 3
        }, 
        "entitiesToMake": "findUsefulResult", 
        "goalMenuKey": "findUsefulMenu", 
        "description": "It's important to you that his life is better for having you in it."
    }, 
    "guiltGoalConstruction": {
        "key": "guiltGoalConstruction", 
        "constructionIdentifier": "guiltGoal", 
        "name": "Constructing - Guilt Partner", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Guilt Partner", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "insecurity": {
        "name": "Insecurity", 
        "image": "trait-339900", 
        "personHeld": "you", 
        "isaacEntities": [
            "crueltyButton", 
            "searchWorthButton", 
            "callousnessButton", 
            "opennessButton", 
            "mistrustJoyButton"
        ], 
        "key": "insecurity", 
        "interactionKeys": [
            "self"
        ]
    }, 
    "oldFailMineButton": {
        "constructionKey": "oldFailMineConstruction", 
        "name": "Old Failings", 
        "entityCost": {
            "will": 2
        }, 
        "image": "tower_mineSocial", 
        "currenciesMade": [
            "pain"
        ], 
        "entityKey": "oldFailMine", 
        "limitingKeys": [
            "oldFailMine", 
            "oldFailMineConstruction"
        ], 
        "key": "oldFailMineButton", 
        "description": "makes pain"
    }, 
    "shareJoyTowerConstruction": {
        "key": "shareJoyTowerConstruction", 
        "constructionIdentifier": "shareJoyTower", 
        "name": "Constructing - Sharing Joy", 
        "image": "trait-aaaaaa99_tower_mineCheer", 
        "currencyRequested": {
            "social": 5
        }, 
        "constructionName": "Sharing Joy", 
        "killOnTransform": 0
    }, 
    "supportCrisisGoal": {
        "key": "supportCrisisGoal", 
        "randomPosition": 0, 
        "name": "Support Partner", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "support": 3
        }, 
        "entitiesToMake": "faithCrisisToHisWork", 
        "goalMenuKey": "supportCrisisMenu"
    }, 
    "needBusyTower": {
        "image": "tower_droop", 
        "activeImage": "tower_droop_activeOutline-0099ff", 
        "name": "Need Help", 
        "key": "needBusyTower", 
        "description": "Converts busy work -> need"
    }, 
    "searchingWorthToInsecurity": {
        "sourceTrait": "searchingWorth", 
        "newTrait": "insecurity", 
        "key": "searchingWorthToInsecurity"
    }, 
    "friendMeditateButton": {
        "constructionKey": "friendMeditateTowerConstruction", 
        "name": "Be Calmed Down", 
        "image": "tower_goalCalmDown-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "friendMeditateTower", 
        "limitingKeys": [
            "friendMeditateTower", 
            "friendMeditateTowerConstruction"
        ], 
        "key": "friendMeditateButton", 
        "subPanel": "Towers", 
        "description": "Converts social -> calm"
    }, 
    "fascinateMenu": {
        "image": "goal_spark-000000", 
        "name": "COMPLETED - Fascinate The Clever Friend", 
        "key": "fascinateMenu"
    }, 
    "resourceModifier": {
        "timeToDeath": 15
    }, 
    "makeSlowWorkFlatMenu": {
        "image": "goal_mineFrustration-000000", 
        "name": "COMPLETED - Make Statement About Slow Work", 
        "key": "makeSlowWorkFlatMenu"
    }, 
    "caringAction": {
        "currenciesRequired": [
            "goodness"
        ], 
        "towerKey": "caringTower", 
        "currenciesToMake": [
            "caring"
        ], 
        "name": "Caring", 
        "key": "caringAction"
    }, 
    "interruptionSwarm": {
        "resourceCount": 3, 
        "name": "Interruption", 
        "image": "tower_mineFrustration", 
        "destination": "himself", 
        "key": "interruptionSwarm", 
        "emotionTags": [
            "anger"
        ], 
        "resourceKeys": "interruptSmall", 
        "activeImage": "tower_mineFrustration_activeOutline-0099ff"
    }, 
    "hisValueDeposit": {
        "randomPosition": 1, 
        "timeToDeath": 120, 
        "image": "tower_trophy", 
        "sourceTrait": "hisWork", 
        "deposit": {
            "value": 10
        }, 
        "key": "hisValueDeposit", 
        "interactionKeys": [
            "himself"
        ], 
        "activeImage": "tower_trophy_activeOutline-0099ff", 
        "name": "Value"
    }, 
    "goodWorkDeposit": {
        "randomPosition": 1, 
        "name": "Good Work", 
        "image": "tower_towerThinkAbout", 
        "sourceTrait": "hisWork", 
        "deposit": {
            "goodWork": 3
        }, 
        "key": "goodWorkDeposit", 
        "activeImage": "tower_towerThinkAbout_activeOutline-0099ff"
    }, 
    "obsessionsTowerConstruction": {
        "key": "obsessionsTowerConstruction", 
        "constructionIdentifier": "obsessionsTower", 
        "name": "Constructing - Obsessions", 
        "image": "trait-aaaaaa99_tower_daydream", 
        "currencyRequested": {
            "obsession": 3
        }, 
        "constructionName": "Obsessions", 
        "killOnTransform": 0
    }, 
    "switchValueDeposit": {
        "entitiesToMake": "valueDeposit", 
        "key": "switchValueDeposit"
    }, 
    "overcomeCrisisMenu": {
        "image": "goal_motivation-000000", 
        "name": "COMPLETED - Overcome Crisis", 
        "key": "overcomeCrisisMenu"
    }, 
    "killStartRelationHimButton": {
        "entitiesToKill": [
            "startRelationHimButton"
        ], 
        "key": "killStartRelationHimButton"
    }, 
    "fascinateGoal": {
        "key": "fascinateGoal", 
        "randomPosition": 0, 
        "name": "Fascinate The Clever Friend", 
        "image": "goal_spark-000000", 
        "currencyRequested": {
            "interesting": 6
        }, 
        "entitiesToMake": "flipClever", 
        "goalMenuKey": "fascinateMenu"
    }, 
    "criticismSwarmYou": {
        "emotionsToAdd": {
            "criticismSmall": 3
        }, 
        "name": "Criticism", 
        "image": "tower_eyeTear", 
        "key": "criticismSwarmYou", 
        "memoryKey": "memory_criticismSwarmYou", 
        "emotionTags": [
            "sadness", 
            "self"
        ], 
        "resourceKey": "criticismSwarmYouMineConstruction", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "takeOutFrustrationMenu": {
        "image": "goal_mineFrustration-000000", 
        "name": "COMPLETED - Take Out Frustrations", 
        "key": "takeOutFrustrationMenu"
    }, 
    "socialWarmMineConstruction": {
        "key": "socialWarmMineConstruction", 
        "constructionIdentifier": "socialWarmMine", 
        "name": "Constructing - Social", 
        "image": "trait-aaaaaa99_tower_mineSocial", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Social", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "hisBadWorkToFaithCrisis": {
        "sourceTrait": "hisBadWork", 
        "newTrait": "faithCrisis", 
        "key": "hisBadWorkToFaithCrisis"
    }, 
    "toughAction": {
        "currenciesRequired": [
            "strength"
        ], 
        "towerKey": "toughTower", 
        "name": "Tough", 
        "key": "toughAction"
    }, 
    "makeComplimentFlatButton": {
        "constructionKey": "makeComplimentFlatGoalConstruction", 
        "name": "Make Complimentary Statement", 
        "image": "goal_mineCheer-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeComplimentFlatGoal", 
        "key": "makeComplimentFlatButton", 
        "description": "Requires social, compliment."
    }, 
    "feedCrisisGoal": {
        "key": "feedCrisisGoal", 
        "randomPosition": 0, 
        "name": "Feed Crisis", 
        "image": "goal_eyeTear-000000", 
        "currencyRequested": {
            "cruelty": 3
        }, 
        "entitiesToMake": [
            "feedCrisisResult", 
            "faithCrisisToHisWork"
        ], 
        "goalMenuKey": "feedCrisisMenu"
    }, 
    "connectFriendsGoal": {
        "key": "connectFriendsGoal", 
        "randomPosition": 0, 
        "name": "Connect to Old Friends", 
        "image": "goal_mineSocial-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": [
            "warm", 
            "clever", 
            "warmPathRelationship", 
            "killConnectFriendsButton"
        ], 
        "goalMenuKey": "connectFriendsMenu"
    }, 
    "worthlessToInsecurity": {
        "sourceTrait": "worthless", 
        "newTrait": "insecurity", 
        "key": "worthlessToInsecurity"
    }, 
    "triggerCrisisMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Trigger Crisis", 
        "key": "triggerCrisisMenu"
    }, 
    "criticismAction": {
        "currenciesRequired": [
            "completeWork", 
            "cruelty"
        ], 
        "towerKey": "criticismTower", 
        "currenciesToMake": [
            "criticism"
        ], 
        "name": "Criticize", 
        "key": "criticismAction"
    }, 
    "support": {
        "name": "support", 
        "key": "support", 
        "tags": [
            "support"
        ]
    }, 
    "casualMedHim": {
        "resourceCount": 1, 
        "name": "Casual Cruelty", 
        "image": "tower_mineCaution", 
        "destination": "himself", 
        "key": "casualMedHim", 
        "emotionTags": [
            "anger"
        ], 
        "resourceKeys": "casualMed", 
        "activeImage": "tower_mineCaution_activeOutline-0099ff"
    }, 
    "triggerCrisisGoalConstruction": {
        "key": "triggerCrisisGoalConstruction", 
        "constructionIdentifier": "triggerCrisisGoal", 
        "name": "Constructing - Trigger Crisis", 
        "image": "trait-aaaaaa99_goal_eyeTear-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Trigger Crisis", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "sharePainResult": {
        "goodEntities": "calmnessDeposit", 
        "badEntities": [
            "aloneFlatYou", 
            "aloneFlatHim"
        ], 
        "key": "sharePainResult"
    }, 
    "towerTickModifier": {
        "timeToDeath": 15
    }, 
    "findUsefulButton": {
        "constructionKey": "findUsefulGoalConstruction", 
        "name": "Find Useful Thing To Do", 
        "image": "goal_spark-000000", 
        "description": "Requires thought.", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "findUsefulGoal", 
        "key": "findUsefulButton", 
        "displayRiskIcon": 1
    }, 
    "helpValueAction": {
        "currenciesRequired": [
            "helpHim"
        ], 
        "towerKey": "helpValueTower", 
        "currenciesToMake": [
            "value"
        ], 
        "name": "Help Value", 
        "key": "helpValueAction"
    }, 
    "criticismSwarmYouMineConstruction": {
        "key": "criticismSwarmYouMineConstruction", 
        "constructionIdentifier": "criticismSwarmYouMine", 
        "name": "Criticism", 
        "image": "tower_eyeTear-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Criticism"
    }, 
    "shameBurst": {
        "emotionsToAdd": {
            "worthlessSmall": 1
        }, 
        "name": "Burst of Shame", 
        "image": "tower_memoryShame-000000", 
        "key": "shameBurst", 
        "memoryKey": "memory_shameBurst", 
        "emotionTags": [
            "sadness", 
            "self"
        ], 
        "resourceKey": "shameBurstMineConstruction", 
        "activeImage": "tower_memoryShame-000000_activeOutline-0099ff"
    }, 
    "frustration": {
        "name": "frustration", 
        "key": "frustration", 
        "tags": [
            "frustration"
        ]
    }, 
    "dreamDeathDeposit": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Death of a Dream", 
        "key": "dreamDeathDeposit", 
        "deposit": {
            "dreamDeath": 3
        }
    }, 
    "traitHelpInfoPanel": {
        "components": [
            "entityManagerComponent"
        ], 
        "helpLines": [
            "Traits are the things that define you as a person.", 
            "They range from the city you live in to your maturity to the people you know.", 
            "They grow with use and you can build towers on them."
        ], 
        "name": "Traits", 
        "key": "traitHelpInfoPanel"
    }, 
    "stateTower": {
        "image": "tower_newNote", 
        "activeImage": "tower_newNote_activeOutline-0099ff", 
        "name": "Statement", 
        "key": "stateTower", 
        "description": "Converts social -> state"
    }, 
    "makeCriticismFlatButton": {
        "constructionKey": "makeCriticismFlatGoalConstruction", 
        "name": "Make Critical Statement", 
        "image": "goal_mineFrustration-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeCriticismFlatGoal", 
        "key": "makeCriticismFlatButton", 
        "description": "Requires state, criticism."
    }, 
    "startConverseButton": {
        "constructionKey": "startConverseGoalConstruction", 
        "name": "Start Conversation", 
        "image": "goal_goalConvinceWife-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "startConverseGoal", 
        "disablingEntities": [
            "conversation"
        ], 
        "key": "startConverseButton", 
        "description": "Requires social."
    }, 
    "flashback_joy": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_joy", 
        "emotionTags": "joy", 
        "resourceKeys": [
            "joy"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes joy"
    }, 
    "himself": {
        "name": "Him", 
        "ai": 1, 
        "image": "trait-aaaaaa_self", 
        "creepHitEntities": [
            "disableHim", 
            "hisEmotionDeposit", 
            "killCapable"
        ], 
        "health": 200, 
        "key": "himself", 
        "focusCount": 5, 
        "y": 21, 
        "x": 11
    }, 
    "feedCrisisMenu": {
        "image": "goal_eyeTear-000000", 
        "completeText": "You seem to have gotten through.", 
        "name": "COMPLETED - Feed Crisis", 
        "key": "feedCrisisMenu"
    }, 
    "memory_oldHurt": {
        "image": "trait-013d70", 
        "memoryEmotions": [
            "sadness"
        ], 
        "key": "memory_oldHurt", 
        "name": "Old Pain"
    }, 
    "truthTowerConstruction": {
        "key": "truthTowerConstruction", 
        "constructionIdentifier": "truthTower", 
        "name": "Constructing - Speak Truth", 
        "image": "trait-aaaaaa99_tower_newNote", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Speak Truth", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "viceMed": {
        "emotion": "joy", 
        "name": "vice", 
        "image": "creepLarge-ffff00", 
        "memoryImage": "memoryJoy", 
        "health": 60, 
        "key": "viceMed"
    }, 
    "guiltButton": {
        "constructionKey": "guiltGoalConstruction", 
        "name": "Guilt Partner", 
        "image": "goal_eyeTear-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "guiltGoal", 
        "key": "guiltButton", 
        "description": "Requires need."
    }, 
    "mistrustJoyTowerConstruction": {
        "key": "mistrustJoyTowerConstruction", 
        "constructionIdentifier": "mistrustJoyTower", 
        "name": "Constructing - Mistrust of Joy", 
        "image": "trait-aaaaaa99_tower_mineCheer", 
        "currencyRequested": {
            "insecure": 3
        }, 
        "constructionName": "Mistrust of Joy", 
        "killOnTransform": 0
    }, 
    "insecurityPathFun": {
        "startKey": "insecurity", 
        "endKey": "fun", 
        "key": "insecurityPathFun"
    }, 
    "learnHimResult": {
        "goodEntities": "partnerInfoDeposit", 
        "badEntities": {
            "explainLearnHimFail": 3
        }, 
        "key": "learnHimResult"
    }, 
    "aloneFlatYouMineConstruction": {
        "key": "aloneFlatYouMineConstruction", 
        "constructionIdentifier": "aloneFlatYouMine", 
        "name": "Feeling Alone", 
        "image": "tower_eyeTear-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Feeling Alone"
    }, 
    "askForBeliefGoal": {
        "key": "askForBeliefGoal", 
        "randomPosition": 0, 
        "name": "Ask For Belief", 
        "image": "goal_trophy-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": "beBelievedGoal", 
        "goalMenuKey": "askForBeliefMenu"
    }, 
    "flashback_guiltMedConstruction": {
        "key": "flashback_guiltMedConstruction", 
        "constructionIdentifier": "flashback_guiltMed", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "warmPathSelfish": {
        "startKey": "warm", 
        "endKey": "selfish", 
        "key": "warmPathSelfish"
    }, 
    "busyWork": {
        "name": "busy work", 
        "key": "busyWork", 
        "tags": [
            "busyWork"
        ]
    }, 
    "casualSwarmHim": {
        "resourceCount": 3, 
        "name": "Casual Cruelty", 
        "image": "tower_mineCaution", 
        "destination": "himself", 
        "key": "casualSwarmHim", 
        "emotionTags": [
            "anger"
        ], 
        "resourceKeys": "casualSmall", 
        "activeImage": "tower_mineCaution_activeOutline-0099ff"
    }, 
    "memory_complimentSwarmYou": {
        "image": "trait-e6e617", 
        "memoryEmotions": [
            "joy"
        ], 
        "key": "memory_complimentSwarmYou", 
        "name": "Compliment"
    }, 
    "helpValueTowerConstruction": {
        "key": "helpValueTowerConstruction", 
        "constructionIdentifier": "helpValueTower", 
        "name": "Constructing - Value From Help", 
        "image": "trait-aaaaaa99_tower_trophy", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Value From Help", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "critical_ext": {
        "personHeld": "you", 
        "image": [
            "trait-ff0066", 
            "trait-E5005B", 
            "trait-FF0070"
        ], 
        "name": "Critical", 
        "key": "critical_ext", 
        "sourceKey": "critical"
    }, 
    "trainPathHelpInfoPanel": {
        "components": [
            "trainPathComponent"
        ], 
        "helpLines": [
            "These are the trains of thought that let you complete tasks by moving things from one building to another."
        ], 
        "name": "Trains", 
        "key": "trainPathHelpInfoPanel"
    }, 
    "findUsefulGoalConstruction": {
        "key": "findUsefulGoalConstruction", 
        "constructionIdentifier": "findUsefulGoal", 
        "name": "Constructing - Find Useful Thing To Do", 
        "image": "trait-aaaaaa99_goal_spark-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Find Useful Thing To Do", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "takeConnectButton": {
        "constructionKey": "takeConnectGoalConstruction", 
        "name": "Take Friend's Connection", 
        "image": "goal_goalMeetNewPerson-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "takeConnectGoal", 
        "key": "takeConnectButton", 
        "description": "Requires will."
    }, 
    "disableMemories": {
        "timeToDeath": 150, 
        "key": "disableMemories"
    }, 
    "distractAction": {
        "currenciesRequired": [
            "social", 
            "need"
        ], 
        "towerKey": "distractTower", 
        "currenciesToMake": [
            "distract"
        ], 
        "name": "Distract", 
        "key": "distractAction"
    }, 
    "relationshipMine": {
        "image": "tower_towerDate", 
        "resourceKeys": [
            "relationshipTime"
        ], 
        "name": "Time Together", 
        "key": "relationshipMine", 
        "activeImage": "tower_towerDate_activeOutline-0099ff"
    }, 
    "flirtHimButton": {
        "aiVal": 4, 
        "constructionKey": "flirtHimGoalConstruction", 
        "name": "Flirt", 
        "image": "goal_heart-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "flirtHimGoal", 
        "key": "flirtHimButton", 
        "interactionKeys": [
            "himself"
        ], 
        "description": [
            "Requires flirtation.", 
            "Makes Info on You."
        ]
    }, 
    "tryNewGoal": {
        "key": "tryNewGoal", 
        "randomPosition": 0, 
        "name": "Try Something New", 
        "image": "goal_spark-000000", 
        "currencyRequested": {
            "will": 6
        }, 
        "entitiesToMake": "tryNewResult", 
        "goalMenuKey": "tryNewMenu", 
        "description": "There has to be something that's right for you."
    }, 
    "sadness": {
        "emotion": "sadness", 
        "name": "sadness", 
        "image": "creep-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 10, 
        "key": "sadness"
    }, 
    "getOverGoodWorkGoalConstruction": {
        "key": "getOverGoodWorkGoalConstruction", 
        "constructionIdentifier": "getOverGoodWorkGoal", 
        "name": "Constructing - Get Over Good Work", 
        "image": "trait-aaaaaa99_goal_weight-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Get Over Good Work", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "guiltFlatYouMine": {
        "resourceCount": 1, 
        "name": "Guilt", 
        "image": "tower_eyeTear", 
        "key": "guiltFlatYouMine", 
        "emotionTags": [
            "sadness", 
            "self", 
            "guiltMed"
        ], 
        "resourceKeys": [
            "guiltMed"
        ], 
        "activeImage": "tower_eyeTear_activeOutline-0099ff", 
        "description": "makes guiltMed"
    }, 
    "goodWork": {
        "name": "goodWork", 
        "key": "goodWork", 
        "tags": [
            "goodWork"
        ]
    }, 
    "speakOfValueMenu": {
        "image": "goal_mineCheer-000000", 
        "name": "COMPLETED - Speak of Your Value", 
        "key": "speakOfValueMenu"
    }, 
    "opennessButton": {
        "constructionKey": "opennessTowerConstruction", 
        "name": "Be Open", 
        "image": "tower_openDoor", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "opennessTower", 
        "limitingKeys": [
            "opennessTower", 
            "opennessTowerConstruction"
        ], 
        "key": "opennessButton", 
        "subPanel": "Towers", 
        "description": "Converts will -> openness"
    }, 
    "explainFindUsefulFail": {
        "completeText": "That was something, but not something useful", 
        "key": "explainFindUsefulFail"
    }, 
    "makeSlowWorkFlatGoalConstruction": {
        "key": "makeSlowWorkFlatGoalConstruction", 
        "constructionIdentifier": "makeSlowWorkFlatGoal", 
        "name": "Constructing - Make Statement About Slow Work", 
        "image": "trait-aaaaaa99_goal_mineFrustration-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Make Statement About Slow Work", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "switchTriggerCrisisButton": {
        "entitiesToMake": "triggerCrisisButton", 
        "key": "switchTriggerCrisisButton"
    }, 
    "rejectMeanlessGoal": {
        "key": "rejectMeanlessGoal", 
        "randomPosition": 0, 
        "name": "Reject Meaninglessness", 
        "image": "goal_openMind-000000", 
        "currencyRequested": {
            "value": 6
        }, 
        "entitiesToMake": "searchingWorthToInsecurity", 
        "goalMenuKey": "rejectMeanlessMenu"
    }, 
    "makeDreamDeathMajorMenu": {
        "image": "goal_eyeTear-000000", 
        "name": "COMPLETED - Talk About Death of Dream", 
        "key": "makeDreamDeathMajorMenu"
    }, 
    "guiltFlatYou": {
        "emotionsToAdd": {
            "guiltMed": 1
        }, 
        "name": "Guilt", 
        "image": "tower_eyeTear", 
        "key": "guiltFlatYou", 
        "memoryKey": "memory_guiltFlatYou", 
        "emotionTags": [
            "sadness", 
            "self"
        ], 
        "resourceKey": "guiltFlatYouMineConstruction", 
        "activeImage": "tower_eyeTear_activeOutline-0099ff"
    }, 
    "quietCriticismGoal": {
        "key": "quietCriticismGoal", 
        "randomPosition": 1, 
        "name": "Quiet Criticism of Self", 
        "makeOnTimeOut": "insecureSwarmYou", 
        "image": "goal_goalCalmDown-000000", 
        "sourceTrait": "critical", 
        "currencyRequested": {
            "will": 6
        }, 
        "goalMenuKey": "quietCriticismMenu", 
        "timeToDeath": 150
    }, 
    "oddity": {
        "name": "oddity", 
        "key": "oddity", 
        "tags": [
            "oddity"
        ]
    }, 
    "hisWork": {
        "sector": [
            0, 
            0
        ], 
        "name": "His Work", 
        "image": "trait-ff66ff", 
        "personHeld": "him", 
        "isaacEntities": [
            "triggerCrisisButton", 
            "hardWorkButton", 
            "completeWorkButton", 
            "needBusyButton"
        ], 
        "key": "hisWork", 
        "interactionKeys": [
            "self", 
            "himself"
        ]
    }, 
    "completeWorkResult": {
        "goodEntities": "completeWorkFull", 
        "badEntities": [
            "hisWorkToHisBadWork", 
            "interestingDeposit"
        ], 
        "key": "completeWorkResult"
    }, 
    "flashback_resentMed": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_resentMed", 
        "emotionTags": "resentMed", 
        "resourceKeys": [
            "resentMed"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes resentMed"
    }, 
    "goodSpendTimeResult": {
        "entitiesToMake": [
            "talkHappy", 
            "jealousyBurst"
        ], 
        "key": "goodSpendTimeResult"
    }, 
    "forceOpennessButton": {
        "constructionKey": "forceOpennessGoalConstruction", 
        "name": "Force Some Openness", 
        "image": "goal_weight-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "forceOpennessGoal", 
        "key": "forceOpennessButton", 
        "description": [
            "Requires will.", 
            "Makes openness."
        ]
    }, 
    "getFeedbackGoalConstruction": {
        "key": "getFeedbackGoalConstruction", 
        "constructionIdentifier": "getFeedbackGoal", 
        "name": "Constructing - Get Feedback", 
        "image": "trait-aaaaaa99_goal_hook-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Get Feedback", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "switchFascinateButton": {
        "entitiesToMake": "fascinateButton", 
        "key": "switchFascinateButton"
    }, 
    "flashback_casualSmallConstruction": {
        "key": "flashback_casualSmallConstruction", 
        "constructionIdentifier": "flashback_casualSmall", 
        "name": "Flashback", 
        "image": "tower_flashback-000000-666666aa", 
        "currencyRequested": {
            "impulse": 1
        }, 
        "constructionName": "Flashback"
    }, 
    "goodness": {
        "name": "goodness", 
        "key": "goodness", 
        "tags": [
            "goodness"
        ]
    }, 
    "casualSwarmYou": {
        "emotionsToAdd": {
            "casualSmall": 3
        }, 
        "name": "Casual Cruelty", 
        "image": "tower_mineCaution", 
        "key": "casualSwarmYou", 
        "memoryKey": "memory_casualSwarmYou", 
        "emotionTags": [
            "anger", 
            "self"
        ], 
        "resourceKey": "casualSwarmYouMineConstruction", 
        "activeImage": "tower_mineCaution_activeOutline-0099ff"
    }, 
    "completeWorkFull": {
        "entitiesToMake": [
            "completeWorkDeposit", 
            "growHisWork", 
            "hisWorkToHisGoodWork", 
            "hisValueDeposit"
        ], 
        "key": "completeWorkFull"
    }, 
    "solveProbeTowerConstruction": {
        "key": "solveProbeTowerConstruction", 
        "constructionIdentifier": "solveProbeTower", 
        "name": "Constructing - Solve Probed Problems", 
        "image": "trait-aaaaaa99_tower_newNote", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Solve Probed Problems", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "makeStupidityFlatButton": {
        "constructionKey": "makeStupidityFlatGoalConstruction", 
        "name": "Make Statement About Stupidity", 
        "image": "goal_mineFrustration-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "makeStupidityFlatGoal", 
        "key": "makeStupidityFlatButton", 
        "description": "Requires state, stupidity."
    }, 
    "supportButton": {
        "constructionKey": "supportTowerConstruction", 
        "name": "Support", 
        "image": "tower_dependence", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "supportTower", 
        "limitingKeys": [
            "supportTower", 
            "supportTowerConstruction"
        ], 
        "key": "supportButton", 
        "description": "Converts cheer -> support"
    }, 
    "selfish": {
        "sector": [
            0, 
            5
        ], 
        "name": "Selfish", 
        "image": "trait-663333", 
        "personHeld": "good", 
        "isaacEntities": [
            "selfishnessMineButton", 
            "askHelpButton", 
            "guiltButton"
        ], 
        "key": "selfish", 
        "interactionKeys": [
            "himself"
        ], 
        "maxLevel": 6
    }, 
    "takeStrengthGoal": {
        "key": "takeStrengthGoal", 
        "randomPosition": 1, 
        "name": "Take Strength From", 
        "image": "goal_weight-000000", 
        "currencyRequested": {
            "strength": 3
        }, 
        "entitiesToMake": "strengthDeposit", 
        "interactionKeys": [
            "himself"
        ], 
        "goalMenuKey": "takeStrengthMenu"
    }, 
    "beSupportedGoal": {
        "key": "beSupportedGoal", 
        "randomPosition": 0, 
        "name": "Take Support", 
        "image": "goal_dependence-000000", 
        "currencyRequested": {
            "support": 3
        }, 
        "entitiesToMake": [
            "relationshipPathStrong", 
            "hurtingPathRelationship", 
            "insecureMinePlaced", 
            "insecureMinePlaced", 
            "beSupportedDone"
        ], 
        "goalMenuKey": "beSupportedMenu"
    }, 
    "youPathInsecurity": {
        "startKey": "you", 
        "endKey": "insecurity", 
        "key": "youPathInsecurity"
    }, 
    "startRelationYouMenu": {
        "image": "goal_dependence-000000", 
        "completeText": "What comes next?", 
        "name": "COMPLETED - Start Relationship", 
        "key": "startRelationYouMenu"
    }, 
    "tryForConnectionYouGoalConstruction": {
        "key": "tryForConnectionYouGoalConstruction", 
        "constructionIdentifier": "tryForConnectionYouGoal", 
        "name": "Constructing - Try For Connection", 
        "image": "trait-aaaaaa99_goal_dependence-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Try For Connection", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "makeComplimentSwarmGoalConstruction": {
        "key": "makeComplimentSwarmGoalConstruction", 
        "constructionIdentifier": "makeComplimentSwarmGoal", 
        "name": "Constructing - Make Swarm of Compliments", 
        "image": "trait-aaaaaa99_goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Make Swarm of Compliments", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "hurtingPathClever": {
        "startKey": "hurting", 
        "endKey": "clever", 
        "key": "hurtingPathClever"
    }, 
    "helpHim": {
        "name": "helped", 
        "key": "helpHim", 
        "tags": [
            "helpHim"
        ]
    }, 
    "role": {
        "exhaustEntities": [
            "killDefineRoleButton", 
            "setDefineRoleDone"
        ], 
        "possiblePairs": [
            [
                "good", 
                "goodPathYou", 
                "goodPathRelationship"
            ], 
            [
                "hurting", 
                "hurtingPathRelationship", 
                "insecurePathHurting"
            ], 
            [
                "warm", 
                "warmPathRelationship", 
                "warmPathYou"
            ]
        ], 
        "key": "role"
    }, 
    "busyWorkMine": {
        "name": "Work Ethic", 
        "image": "tower_mineWill", 
        "key": "busyWorkMine", 
        "interactionKeys": [
            "himself"
        ], 
        "resourceKeys": [
            "will"
        ], 
        "activeImage": "tower_mineWill_activeOutline-0099ff"
    }, 
    "doFunGoal": {
        "key": "doFunGoal", 
        "randomPosition": 0, 
        "name": "Do Something Fun!", 
        "image": "goal_mineCheer-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": [
            "viceFlatHim", 
            "viceFlatYou"
        ], 
        "goalMenuKey": "doFunMenu"
    }, 
    "trait": {
        "playerKillable": "true"
    }, 
    "flashback_oldFailSmall": {
        "resourceCount": 1, 
        "name": "Flashback", 
        "image": "tower_flashback-000000", 
        "key": "flashback_oldFailSmall", 
        "emotionTags": "oldFailSmall", 
        "resourceKeys": [
            "oldFailSmall"
        ], 
        "activeImage": "tower_flashback-000000_activeOutline-0099ff", 
        "description": "makes oldFailSmall"
    }, 
    "you": {
        "sector": [
            0, 
            0
        ], 
        "name": "You", 
        "image": "trait-99ff66", 
        "personHeld": "you", 
        "isaacEntities": [
            "selfDistractionButton", 
            "obsessionsButton", 
            "selfValueButton", 
            "toughButton", 
            "calmnessButton"
        ], 
        "key": "you", 
        "interactionKeys": [
            "self"
        ], 
        "maxLevel": 8, 
        "startManagedEntities": [
            "anxietyMine", 
            "anxietyMine", 
            "selfDistractionTower"
        ], 
        "tendPosition": [
            0, 
            0
        ], 
        "description": "It just feels like there's someone better you could be instead."
    }, 
    "distractTowerConstruction": {
        "key": "distractTowerConstruction", 
        "constructionIdentifier": "distractTower", 
        "name": "Constructing - Distract", 
        "image": "trait-aaaaaa99_tower_mineCheer", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Distract", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "takeConnectBranch": {
        "flagToCheck": "takeConnectDone", 
        "key": "takeConnectBranch", 
        "notFlagEntities": "takeConnectButton"
    }, 
    "oldFailSmall": {
        "emotion": "sadness", 
        "name": "old failures", 
        "image": "creep-0000ff", 
        "memoryImage": "memorySadness", 
        "health": 20, 
        "key": "oldFailSmall"
    }, 
    "defineHelpGoal": {
        "key": "defineHelpGoal", 
        "randomPosition": 0, 
        "name": "Define Yourself as Helpful", 
        "image": "goal_heart-000000", 
        "currencyRequested": {
            "thought": 3, 
            "insecure": 3
        }, 
        "entitiesToMake": "searchingWorthToHelpful", 
        "goalMenuKey": "defineHelpMenu", 
        "description": "It's something like being worth something."
    }, 
    "needHelpGoal": {
        "key": "needHelpGoal", 
        "randomPosition": 0, 
        "name": "Need Help Yourself", 
        "image": "goal_minePain-000000", 
        "currencyRequested": {
            "need": 3
        }, 
        "entitiesToMake": "flipGood", 
        "goalMenuKey": "needHelpMenu"
    }, 
    "obsessionsTower": {
        "description": "Uses obsession to calm anger, joy, sadness", 
        "charges": 3, 
        "image": "tower_daydream", 
        "damage": 60, 
        "damageMultipliers": {
            "anger": 1, 
            "joy": 1, 
            "sadness": 1
        }, 
        "impulseTicks": 3, 
        "key": "obsessionsTower", 
        "activeImage": "tower_daydream_activeOutline-0099ff", 
        "name": "Obsessions"
    }, 
    "cruelty": {
        "name": "cruelty", 
        "key": "cruelty", 
        "tags": [
            "cruelty"
        ]
    }, 
    "majorButton": {
        "constructionKey": "majorTowerConstruction", 
        "name": "Major Statement", 
        "image": "tower_newNote", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "majorTower", 
        "limitingKeys": [
            "majorTower", 
            "majorTowerConstruction"
        ], 
        "key": "majorButton", 
        "subPanel": "Towers", 
        "description": "Converts social -> major"
    }, 
    "searchWorthGoalConstruction": {
        "key": "searchWorthGoalConstruction", 
        "constructionIdentifier": "searchWorthGoal", 
        "name": "Constructing - Why Are You Like This?", 
        "image": "trait-aaaaaa99_goal_memoryLearn-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Why Are You Like This?", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "flirtation": {
        "name": "flirtation", 
        "key": "flirtation", 
        "tags": [
            "flirtation"
        ]
    }, 
    "setDefineRoleDone": {
        "flag": "defineRoleDone", 
        "key": "setDefineRoleDone"
    }, 
    "appreciateWorkGoalConstruction": {
        "key": "appreciateWorkGoalConstruction", 
        "constructionIdentifier": "appreciateWorkGoal", 
        "name": "Constructing - Appreciate His Work", 
        "image": "trait-aaaaaa99_goal_towerFlirt-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Appreciate His Work", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "hisGoodWork": {
        "sector": [
            0, 
            0
        ], 
        "name": "His Good Work", 
        "image": "trait-9966ff", 
        "personHeld": "him", 
        "isaacEntities": [
            "getOverGoodWorkButton", 
            "deriveWorkTopicButton"
        ], 
        "key": "hisGoodWork", 
        "interactionKeys": [
            "himself"
        ]
    }, 
    "aloneFlatYouMine": {
        "resourceCount": 1, 
        "name": "Feeling Alone", 
        "image": "tower_eyeTear", 
        "key": "aloneFlatYouMine", 
        "emotionTags": [
            "sadness", 
            "self", 
            "aloneMed"
        ], 
        "resourceKeys": [
            "aloneMed"
        ], 
        "activeImage": "tower_eyeTear_activeOutline-0099ff", 
        "description": "makes aloneMed"
    }, 
    "makeSlowWorkSwarmGoalConstruction": {
        "key": "makeSlowWorkSwarmGoalConstruction", 
        "constructionIdentifier": "makeSlowWorkSwarmGoal", 
        "name": "Constructing - Make Swarm About Slow Work", 
        "image": "trait-aaaaaa99_goal_mineFrustration-000000", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Make Swarm About Slow Work", 
        "killOnTransform": 1, 
        "description": "It takes will to start something new."
    }, 
    "topicDeposit": {
        "image": "tower_dependence", 
        "activeImage": "tower_dependence_activeOutline-0099ff", 
        "name": "Topic", 
        "key": "topicDeposit", 
        "deposit": {
            "topic": 3
        }
    }, 
    "accuseSelfishMenu": {
        "image": "goal_goalAskAbout-000000", 
        "name": "COMPLETED - Accuse of Selfishness", 
        "key": "accuseSelfishMenu"
    }, 
    "selfValueTower": {
        "description": "Uses value to calm anger, sadness", 
        "charges": 3, 
        "image": "tower_trophy", 
        "damage": 60, 
        "damageMultipliers": {
            "anger": 1, 
            "sadness": 1
        }, 
        "impulseTicks": 3, 
        "key": "selfValueTower", 
        "activeImage": "tower_trophy_activeOutline-0099ff", 
        "name": "Valuing Yourself"
    }, 
    "complimentFlatYou": {
        "emotionsToAdd": {
            "complimentMed": 1
        }, 
        "name": "Compliment", 
        "image": "tower_memoryRing", 
        "key": "complimentFlatYou", 
        "memoryKey": "memory_complimentFlatYou", 
        "emotionTags": [
            "joy", 
            "self"
        ], 
        "resourceKey": "complimentFlatYouMineConstruction", 
        "activeImage": "tower_memoryRing_activeOutline-0099ff"
    }, 
    "thankGoal": {
        "key": "thankGoal", 
        "randomPosition": 1, 
        "name": "Thank For Usefulness", 
        "makeOnTimeOut": {
            "guiltEmo": 100, 
            "flipGood": 50
        }, 
        "image": "goal_heart-000000", 
        "currencyRequested": {
            "social": 3
        }, 
        "entitiesToMake": "switchValueDeposit", 
        "goalMenuKey": "thankMenu", 
        "timeToDeath": 150
    }, 
    "complimentAction": {
        "currenciesRequired": [
            "completeWork", 
            "generosity"
        ], 
        "towerKey": "complimentTower", 
        "currenciesToMake": [
            "compliment"
        ], 
        "name": "Compliment", 
        "key": "complimentAction"
    }, 
    "supportCrisisButton": {
        "constructionKey": "supportCrisisGoalConstruction", 
        "name": "Support Partner", 
        "image": "goal_dependence-000000", 
        "entityCost": {
            "will": 2
        }, 
        "entityKey": "supportCrisisGoal", 
        "key": "supportCrisisButton", 
        "interactionKeys": [
            "self"
        ], 
        "description": "Requires support."
    }, 
    "willMineConstruction": {
        "key": "willMineConstruction", 
        "constructionIdentifier": "willMine", 
        "name": "Constructing - Drive", 
        "image": "trait-aaaaaa99_tower_mineWill", 
        "currencyRequested": {
            "will": 2
        }, 
        "constructionName": "Drive", 
        "killOnTransform": 0, 
        "description": "It takes will to start something new."
    }, 
    "beHelpGoal": {
        "key": "beHelpGoal", 
        "randomPosition": 1, 
        "name": "Be Helpful", 
        "image": "goal_heart-000000", 
        "currencyRequested": {
            "will": 3
        }, 
        "entitiesToMake": "helpDeposit", 
        "goalMenuKey": "beHelpMenu"
    }, 
    "faithCrisis": {
        "sector": [
            0, 
            8
        ], 
        "name": "Crisis of Faith", 
        "image": "trait-660000", 
        "personHeld": "him", 
        "isaacEntities": [
            "overcomeCrisisButton", 
            "switchFeedCrisisButton", 
            "switchSupportCrisisButton"
        ], 
        "key": "faithCrisis", 
        "interactionKeys": [
            "self", 
            "himself"
        ], 
        "maxLevel": 6
    }, 
    "push": {
        "name": "push", 
        "key": "push", 
        "tags": [
            "push"
        ]
    }, 
    "obsessMenu": {
        "image": "goal_motivation-000000", 
        "name": "COMPLETED - Obsess", 
        "key": "obsessMenu"
    }
};

var ecs = {
    memoryComponent: function(args){
        if (args.memoryEmotions === undefined){ throw "ECS fail " + args.key + " missing memoryEmotions"; }
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        if (args.source2Key === undefined){ throw "ECS fail " + args.key + " missing source2Key"; }
        return {
            coreMemory: false,
            source2Key: args['source2Key'],
            ticksToCoreMemory: 180,
            flashbackFunction: flashbackFunction,
            sourceKey: args['sourceKey'],
            flashbackCount: 1,
            memoryEmotions: args['memoryEmotions']
        };
    },
    memoryEmotionSource: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            emotionSourceComponent: ecs.emotionSourceComponent(args),
            createExecutables: [ecs.emotionSourceCreateExec(args), ecs.killEntity(args)]
        };
    },
    obsessButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessButton)));
        return ecs.goalButton(args);
    },
    winButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.winButton)));
        return ecs.goalButton(args);
    },
    singleUseTrainPathComponent: function(args){
        return {
            makeTrain: singleUseMakeTrain,
            trainId: undefined,
            trainStops: args['trainStops'],
            killTrainPath: undefined,
            stoppable: false,
            trainKey: PARAMETERS.carryTrain,
            canMakeTrain: canMakeTrain,
            requiresFullPath: (args["requiresFullPath"] === undefined) ? true : args["requiresFullPath"],
            getKillTrainPath: getKillTrainPath,
            trainsToMake: 1,
            trainStartId: args['trainStartId'],
            paused: false,
            baseMakeTrain: makeTrain,
            allPaths: [],
            trainColor: undefined
        };
    },
    utilityEntityRenderComponent: function(args){
        return {
            insetColor: "#000000",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "opaqueBack",
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            priority: 19,
            render: utilityEntityRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            showAllBuildingPanel: undefined,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            specificRender: args['specificRender'],
            drawHelpButton: drawHelpButton
        };
    },
    hisWork_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisWork_ext)));
        return ecs.sourceExtension(args);
    },
    callousnessAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.callousnessAction)));
        return ecs.currencyAction(args);
    },
    timedRenderComponent: function(args){
        if (args.nextRenderComponent === undefined){ throw "ECS fail " + args.key + " missing nextRenderComponent"; }
        if (args.renderWhileTimed === undefined){ throw "ECS fail " + args.key + " missing renderWhileTimed"; }
        return {
            renderWhileTimed: args['renderWhileTimed'],
            render: timedRender,
            nextRenderComponent: args['nextRenderComponent'],
            timeDrawn: 0,
            renderTime: (args["renderTime"] === undefined) ? 0.15 : args["renderTime"],
            renderState: "default",
            priority: args['priority']
        };
    },
    slowWorkSwarm: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.slowWorkSwarm)));
        return ecs.instantEmotionResource(args);
    },
    himSupportButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.himSupportButton)));
        return ecs.towerButton(args);
    },
    fascinateGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.fascinateGoalConstruction)));
        return ecs.construction(args);
    },
    guiltFlatYouMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.guiltFlatYouMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    makeRandomMultiple: function(args){
        return {
            replaceMarker: ecs.makeRandomMultipleReplaceMarker(args)
        };
    },
    askForBeliefMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askForBeliefMenu)));
        return ecs.goalCompleteMenu(args);
    },
    doFunMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.doFunMenu)));
        return ecs.goalCompleteMenu(args);
    },
    openUpGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.openUpGoalConstruction)));
        return ecs.construction(args);
    },
    gameEnd: function(args){
        return {
            renderComponents: [ecs.gameEndRenderComponent(args)],
            pauseComponent: ecs.pauseComponent(args),
            gameEndComponent: ecs.gameEndComponent(args)
        };
    },
    viceFlatYouMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.viceFlatYouMine)));
        return ecs.emotionResource(args);
    },
    memoryConstruction: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        return {
            junctionComponent: ecs.junctionComponent(args),
            rendererComponents: [ecs.constructionRenderComponent(args), ecs.progressRenderComponent(args)],
            personHeldComponent: ecs.personHeldComponent(args),
            managedComponent: ecs.managedComponent(args),
            constructionComponent: ecs.memoryConstructionComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)].concat([ecs.openMenu(args)]),
            focusPathStopComponent: ecs.constructionFocusPathStopComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            tickComponent: ecs.constructionTickComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    startConverseMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startConverseMenu)));
        return ecs.goalCompleteMenu(args);
    },
    stateAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.stateAction)));
        return ecs.currencyAction(args);
    },
    shareJoyAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.shareJoyAction)));
        return ecs.currencyAction(args);
    },
    towerComponent: function(args){
        return {
            possibleCurrencyActionForTower: possibleCurrencyActionForTower,
            storeCount: 3,
            canDamageTower: canDamageTower,
            currencyActionForTower: currencyActionForTower
        };
    },
    takeOutFrustrationGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeOutFrustrationGoal)));
        return ecs.worldGoal(args);
    },
    currencyRenderEntity: function(args){
        args["key"] = PARAMETERS.currencyRenderEntity;
        return {
            currencyRenderEntityComponent: ecs.currencyRenderEntityComponent(args),
            identityComponent: ecs.identityComponent(args),
            rendererComponents: [ecs.allCurrencyRenderClear(args), ecs.allCurrencyRenderComponent(args)]
        };
    },
    calmnessMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmnessMineConstruction)));
        return ecs.construction(args);
    },
    criticismSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismSmall)));
        return ecs.creep(args);
    },
    noticeThingMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.noticeThingMenu)));
        return ecs.goalCompleteMenu(args);
    },
    tiredSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tiredSmall)));
        return ecs.creep(args);
    },
    reachOutGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reachOutGoal)));
        return ecs.worldGoal(args);
    },
    calmnessTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmnessTower)));
        return ecs.tower(args);
    },
    acceptConnectionHimGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.acceptConnectionHimGoal)));
        return ecs.worldGoal(args);
    },
    socialAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialAction)));
        return ecs.currencyAction(args);
    },
    currencyRenderComponent: function(args){
        return {
            priority: 12,
            image: "currency",
            renderState: "default",
            render: currencyRender,
            renderPos: undefined
        };
    },
    quietTimeMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.quietTimeMenu)));
        return ecs.goalCompleteMenu(args);
    },
    shareJoyTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.shareJoyTower)));
        return ecs.tower(args);
    },
    path: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.path)));
        args["y"] = args['start'][1];
        args["x"] = args['start'][0];
        args["name"] = 'path(' + args.x + ',' + args.y + ')';;
        args["key"] = 'path_' + args.x + '_' + args.y + '_' + args.end[0] + '_' + args.end[1];;
        return {
            rendererComponents: [ecs.pathConnectRenderComponent(args)],
            pathMoveComponent: ecs.pathMoveComponent(args),
            createExecutables: [ecs.duplicatePathExec(args)],
            healthComponent: ecs.hundredHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    calmnessTowerPlaced: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmnessTowerPlaced)));
        return ecs.placedTower(args);
    },
    startRelationYouButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startRelationYouButton)));
        return ecs.goalButton(args);
    },
    fadingMemoryComponent: function(args){
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        if (args.source2Key === undefined){ throw "ECS fail " + args.key + " missing source2Key"; }
        return {
            oldTrait: undefined,
            sourceKey: args['sourceKey'],
            source2Key: args['source2Key']
        };
    },
    creepCreateExec: function(args){
        if (args.sourceId === undefined){ throw "ECS fail " + args.key + " missing sourceId"; }
        return {
            firstTick: (args["firstTick"] === undefined) ? true : args["firstTick"],
            makeTrain: (args["makeTrain"] === undefined) ? true : args["makeTrain"],
            execute: creepCreateExec,
            creepTrainPath: PARAMETERS.singleUseTrainPath,
            sourceId: args['sourceId'],
            destination: (args["destination"] === undefined) ? PARAMETERS.self : args["destination"]
        };
    },
    checkManagedComponentExec: function(args){
        return {
            execute: checkManagedComponent
        };
    },
    sadnessMap: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sadnessMap)));
        return ecs.emotionResourceMap(args);
    },
    criticism: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticism)));
        return ecs.currency(args);
    },
    currencyOverload: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            currencyOverloadComponent: ecs.currencyOverloadComponent(args)
        };
    },
    damageComponent: function(args){
        args["charges"] = (args["charges"] === undefined) ? 5 : args["charges"];
        if (args.damageMultipliers === undefined){ throw "ECS fail " + args.key + " missing damageMultipliers"; }
        if (args.charges === undefined){ throw "ECS fail " + args.key + " missing charges"; }
        return {
            checkTargetEntity: checkTargetEntity,
            ticks: 0,
            charges: args['charges'],
            targetCount: (args["targetCount"] === undefined) ? 1 : args["targetCount"],
            damage: (args["damage"] === undefined) ? 10 : args["damage"],
            damageMultipliers: args['damageMultipliers'],
            hitPos: undefined,
            maxCharges: args['charges'],
            calculateDamage: calculateDamage,
            getHitPos: getHitPos,
            impulseTicks: (args["impulseTicks"] === undefined) ? 0 : args["impulseTicks"]
        };
    },
    reinforceComplimentMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reinforceComplimentMenu)));
        return ecs.goalCompleteMenu(args);
    },
    switchSupportCrisisButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.switchSupportCrisisButton)));
        return ecs.switch(args);
    },
    casualEmo: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.casualEmo)));
        return ecs.splitReplace(args);
    },
    flashback_joyConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_joyConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    insecurePathHurting: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecurePathHurting)));
        return ecs.pathMaker(args);
    },
    calmnessAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmnessAction)));
        return ecs.currencyAction(args);
    },
    criticismTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismTower)));
        return ecs.tower(args);
    },
    acceptConnectionHimMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.acceptConnectionHimMenu)));
        return ecs.goalCompleteMenu(args);
    },
    insecurity: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecurity)));
        return ecs.trait(args);
    },
    overcomeCrisisGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.overcomeCrisisGoal)));
        return ecs.worldGoal(args);
    },
    aliveMakeComponent: function(args){
        return {
            focusTick: aliveMakeFocusTick,
            aliveEntities: (args["aliveEntities"] === undefined) ? [] : args["aliveEntities"]
        };
    },
    socialTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialTower)));
        return ecs.tower(args);
    },
    calm: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calm)));
        return ecs.currency(args);
    },
    sourceExtensionRenderComponent: function(args){
        return {
            outlineImage: "activeOutline",
            render: sourceExtensionRender,
            wobble: 0,
            image: args['image'],
            priority: 5,
            timeToBlink: 1,
            newImage: "newOutline",
            getWobble: getWobble,
            renderState: "default",
            disabledImage: "trait-aaaaaa"
        };
    },
    getOverGoodWorkMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getOverGoodWorkMenu)));
        return ecs.goalCompleteMenu(args);
    },
    appreciateWorkMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.appreciateWorkMenu)));
        return ecs.goalCompleteMenu(args);
    },
    trainPathMaker: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            rendererComponents: [ecs.trainPathMakerHighlightRenderComponent(args)],
            killExecutables: [ecs.trainPathMakerKill(args)],
            trainPathMakerComponent: ecs.trainPathMakerComponent(args),
            tickComponent: ecs.trainPathMakerTickComponent(args)
        };
    },
    warm: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.warm)));
        return ecs.trait(args);
    },
    goodnessMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goodnessMineButton)));
        return ecs.resourceButton(args);
    },
    calmPartnerButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmPartnerButton)));
        return ecs.goalButton(args);
    },
    startRelationHimMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startRelationHimMenu)));
        return ecs.goalCompleteMenu(args);
    },
    utilityPanel: function(args){
        return {
            panelComponent: ecs.setPanelComponent(args),
            absolutePositionComponent: ecs.utilityPanelAbsolutePositionComponent(args),
            rendererComponents: [ecs.utilityEntityRenderComponent(args)],
            uiClickComponent: ecs.panelUiClickComponent(args)
        };
    },
    carryTrain: function(args){
        return {
            rendererComponents: [ecs.trainRenderComponent(args)],
            trainComponent: ecs.trainComponent(args),
            trainVelocityComponent: ecs.trainVelocityComponent(args),
            createExecutables: [ecs.trainCreateExec(args)],
            killExecutables: [ecs.trainKillExec(args)],
            tickComponent: ecs.carryTrainTickComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            positionComponent: ecs.positionComponent(args)
        };
    },
    currencyRenderEntityComponent: function(args){
        return {
            addCurrencyToRender: addCurrencyToRender,
            currenciesToRender: []
        };
    },
    tryNewMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryNewMenu)));
        return ecs.goalCompleteMenu(args);
    },
    nextDayEntity: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            dayResponseComponent: ecs.nextDayEntityDayResponseComponent(args)
        };
    },
    hisGoodWork_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisGoodWork_ext)));
        return ecs.sourceExtension(args);
    },
    currencyBoost: function(args){
        return {
            rendererComponents: [ecs.boostRenderComponent(args)],
            boostSlotComponent: ecs.boostSlotComponent(args),
            createExecutables: [ecs.randomOpenPositionExec(args)],
            currencyBoostComponent: ecs.currencyBoostComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args)
        };
    },
    activateRenderComponent: function(args){
        return {
            priority: 2,
            renderState: "default",
            activated: false,
            render: activateRender
        };
    },
    currency: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.currency)));
        args["tags"] = (args.tags) ? args.tags.concat([args.key]) : [args.key];
        return {
            pathVelocityComponent: ecs.pathVelocityComponent(args),
            rendererComponents: [ecs.currencyRenderComponent(args)],
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            dayResponseComponent: (args.checkDayEnd) ? ecs.currencyDayResponseComponent(args) : undefined
        };
    },
    autoPathMaker: function(args){
        return {
            replaceMarker: ecs.autoPathReplaceMarker(args)
        };
    },
    askAboutRestlessGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askAboutRestlessGoalConstruction)));
        return ecs.construction(args);
    },
    beSupportedButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.beSupportedButton)));
        return ecs.goalButton(args);
    },
    good_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.good_ext)));
        return ecs.sourceExtension(args);
    },
    crueltyTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.crueltyTowerConstruction)));
        return ecs.construction(args);
    },
    makeComplimentFlatGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeComplimentFlatGoalConstruction)));
        return ecs.construction(args);
    },
    autosaveTickComponent: function(args){
        return {
            lastChapterKey: "chapter1",
            tick: autosaveTick,
            ticksToAutosave: 1
        };
    },
    insecure: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecure)));
        return ecs.currency(args);
    },
    flashback_worthlessSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_worthlessSmall)));
        return ecs.emotionResource(args);
    },
    takeOutFrustrationGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeOutFrustrationGoalConstruction)));
        return ecs.construction(args);
    },
    oldFailMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldFailMed)));
        return ecs.creep(args);
    },
    defineRoleMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.defineRoleMenu)));
        return ecs.goalCompleteMenu(args);
    },
    capable_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.capable_ext)));
        return ecs.sourceExtension(args);
    },
    emotionSourceCreateExec: function(args){
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        if (args.resourceKey === undefined){ throw "ECS fail " + args.key + " missing resourceKey"; }
        if (args.memoryKey === undefined){ throw "ECS fail " + args.key + " missing memoryKey"; }
        return {
            resourceKey: args['resourceKey'],
            sourceKey: args['sourceKey'],
            execute: emotionSourceCreateExec,
            memoryKey: args['memoryKey']
        };
    },
    tryForConnectionHimGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryForConnectionHimGoal)));
        return ecs.worldGoal(args);
    },
    angerMap: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.angerMap)));
        return ecs.emotionResourceMap(args);
    },
    makeOldFailFlatMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeOldFailFlatMenu)));
        return ecs.goalCompleteMenu(args);
    },
    trainCreateExec: function(args){
        if (args.trainPath === undefined){ throw "ECS fail " + args.key + " missing trainPath"; }
        if (args.trainStartId === undefined){ throw "ECS fail " + args.key + " missing trainStartId"; }
        return {
            trainStartId: args['trainStartId'],
            execute: trainCreateExec,
            carriageKey: PARAMETERS.carriage,
            trainPath: args['trainPath']
        };
    },
    timedScaleRenderComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            timeDrawn: 0,
            render: timedRender,
            image: args['image'],
            nextRenderComponent: args['nextRenderComponent'],
            renderWhileTimed: args['renderWhileTimed'],
            renderTime: (args["renderTime"] === undefined) ? 0.15 : args["renderTime"],
            renderWhenTimed: timedScaleRenderWhenTimed,
            renderState: "default",
            priority: args['priority']
        };
    },
    changeOpinion: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            personHeldComponent: ecs.personHeldComponent(args),
            createExecutables: [ecs.changeOpinionExec(args), ecs.killEntity(args)]
        };
    },
    hisBadWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisBadWork)));
        return ecs.trait(args);
    },
    winGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.winGoalConstruction)));
        return ecs.construction(args);
    },
    towerButton: function(args){
        args["subPanel"] = (args["subPanel"] === undefined) ? "Towers" : args["subPanel"];
        args["multiTrait"] = (args["multiTrait"] === undefined) ? false : args["multiTrait"];
        return {
            healthComponent: ecs.singleHealthComponent(args),
            uiActionComponent: ecs.buttonUiActionComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            buttonControlComponent: ecs.towerControlComponent(args),
            createExecutables: [ecs.markTraitNew(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            killExecutables: [ecs.killTowerButtonExec(args)],
            descriptionComponent: ecs.descriptionComponent(args),
            uniqueComponent: (args.timeToDeath === undefined && !args.multiTrait) ? ecs.uniqueComponent(args) : undefined,
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    memory_insecureSwarmYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_insecureSwarmYou)));
        return ecs.memory(args);
    },
    focusTickAliveMakerComponent: function(args){
        if (args.aliveEntities === undefined){ throw "ECS fail " + args.key + " missing aliveEntities"; }
        return {
            focusTick: aliveMakerFocusTick,
            aliveEntities: args['aliveEntities']
        };
    },
    goodPathRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goodPathRelationship)));
        return ecs.pathMaker(args);
    },
    insecurityPathWarm: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecurityPathWarm)));
        return ecs.pathMaker(args);
    },
    pointCounter: function(args){
        return {
            pointCounterComponent: ecs.pointCounterComponent(args),
            notificationComponents: [ecs.pointCounterNotificationComponent(args)]
        };
    },
    carryTrainTickComponent: function(args){
        return {
            tick: carryTrainTick
        };
    },
    dayPanelRenderComponent: function(args){
        return {
            flashTimer: 0,
            dayActions: undefined,
            insetColor: "#000000",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "opaqueBack",
            displayGameStage: undefined,
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            priority: 19,
            render: dayPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            showPausingEntity: showPausingEntity,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            specificRender: args['specificRender'],
            drawHelpButton: drawHelpButton
        };
    },
    quietTimeGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.quietTimeGoalConstruction)));
        return ecs.construction(args);
    },
    fishComplimentsMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.fishComplimentsMenu)));
        return ecs.goalCompleteMenu(args);
    },
    makeSlowWorkFlatButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeSlowWorkFlatButton)));
        return ecs.goalButton(args);
    },
    viceAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.viceAction)));
        return ecs.currencyAction(args);
    },
    indulgeViceMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.indulgeViceMenu)));
        return ecs.goalCompleteMenu(args);
    },
    frustrationMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.frustrationMine)));
        return ecs.memoryResource(args);
    },
    trainPathComponent: function(args){
        if (args.trainStartId === undefined){ throw "ECS fail " + args.key + " missing trainStartId"; }
        if (args.trainStops === undefined){ throw "ECS fail " + args.key + " missing trainStops"; }
        return {
            makeTrain: makeTrain,
            trainId: undefined,
            trainStops: args['trainStops'],
            killTrainPath: undefined,
            stoppable: (args["stoppable"] === undefined) ? true : args["stoppable"],
            trainKey: PARAMETERS.train,
            canMakeTrain: canMakeTrain,
            requiresFullPath: (args["requiresFullPath"] === undefined) ? true : args["requiresFullPath"],
            getKillTrainPath: getKillTrainPath,
            baseMakeTrain: makeTrain,
            trainStartId: args['trainStartId'],
            paused: false,
            allPaths: [],
            trainColor: undefined
        };
    },
    takeSupportTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeSupportTower)));
        return ecs.tower(args);
    },
    randomOpenPositionExec: function(args){
        return {
            execute: randomOpenPositionExec,
            startEntityKey: (args["startEntityKey"] === undefined) ? undefined : args["startEntityKey"],
            startPos: (args.source && args.source.positionComponent) ? [args.source.positionComponent.x, args.source.positionComponent.y] : undefined,
            minSelfDist: (args["minSelfDist"] === undefined) ? 0 : args["minSelfDist"]
        };
    },
    setFlagExec: function(args){
        if (args.flag === undefined){ throw "ECS fail " + args.key + " missing flag"; }
        return {
            flagValue: (args["flagValue"] === undefined) ? true : args["flagValue"],
            execute: setFlagExec,
            flag: args['flag']
        };
    },
    flashback_worthlessMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_worthlessMed)));
        return ecs.emotionResource(args);
    },
    generousAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.generousAction)));
        return ecs.currencyAction(args);
    },
    memoryTower: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        args["isPathEnd"] = (args["isPathEnd"] === undefined) ? (args.damageMultipliers ? true : false) : args["isPathEnd"];
        args["tags"] = (args["tags"] === undefined) ? [args.key] : args["tags"];
        return {
            junctionComponent: ecs.junctionComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args), ecs.damageRenderComponent(args)],
            focusTickResponseComponent: ecs.towerFocusTickResponseComponent(args),
            managedComponent: ecs.managedComponent(args),
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            damageComponent: (args.damageMultipliers) ? ecs.damageComponent(args) : undefined,
            healthModifyComponent: ecs.healthModifyComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)].concat([ecs.towerCreateExec(args)]),
            focusPathStopComponent: ecs.towerFocusPathStopComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            tickComponent: ecs.towerTickComponent(args),
            towerComponent: ecs.towerComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    personCurrency: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.personCurrency)));
        args["tags"] = (args.tags) ? args.tags.concat([args.key]) : [args.key];
        return {
            pathVelocityComponent: ecs.pathVelocityComponent(args),
            rendererComponents: [ecs.currencyRenderComponent(args)],
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            dayResponseComponent: (args.checkDayEnd) ? ecs.currencyDayResponseComponent(args) : undefined
        };
    },
    memoryResource: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        return {
            interactionComponent: ecs.interactionComponent(args),
            junctionComponent: ecs.junctionComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args)],
            focusTickResponseComponent: ecs.memoryResourceFocusTickResponseComponent(args),
            managedComponent: ecs.managedComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)],
            focusPathStopComponent: ecs.resourceFocusPathStopComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killResourceCurrencies(args)],
            descriptionComponent: ecs.descriptionComponent(args),
            resourceComponent: ecs.resourceComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    startRelationHimGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startRelationHimGoalConstruction)));
        return ecs.construction(args);
    },
    allowWeaknessMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.allowWeaknessMenu)));
        return ecs.goalCompleteMenu(args);
    },
    progressRenderComponent: function(args){
        return {
            priority: 10,
            progressX: (args["progressX"] === undefined) ? 20 : args["progressX"],
            progressY: (args["progressY"] === undefined) ? 27 : args["progressY"],
            renderState: "default",
            render: progressRender
        };
    },
    chapterPanel: function(args){
        args["y"] = 5;
        args["x"] = 5;
        args["key"] = PARAMETERS.chapterPanel;
        args["size"] = [500, 300];
        return {
            rendererComponents: [ecs.chapterPanelRenderComponent(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            panelComponent: ecs.panelComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    tryForConnectionYouGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryForConnectionYouGoalConstruction)));
        return ecs.construction(args);
    },
    personCurrencyAction: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args),
            currencyActionComponent: ecs.currencyActionComponent(args)
        };
    },
    loosenUpGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.loosenUpGoal)));
        return ecs.worldGoal(args);
    },
    hardWorkGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hardWorkGoal)));
        return ecs.worldGoal(args);
    },
    timeForceComponent: function(args){
        return {
            ticksPerTick: _.last(PARAMETERS.ticksPerTick)
        };
    },
    creepDeath: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            rendererComponents: [ecs.creepDeathRenderComponent(args)]
        };
    },
    selfishnessMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfishnessMineButton)));
        return ecs.resourceButton(args);
    },
    strong_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.strong_ext)));
        return ecs.sourceExtension(args);
    },
    hitRenderComponent: function(args){
        return {
            priority: 9,
            wasHit: false,
            renderState: "default",
            render: hitRender
        };
    },
    rechargeTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.rechargeTower)));
        return ecs.memoryTower(args);
    },
    makeExtraPathsExec: function(args){
        return {
            execute: makeExtraPathsExec
        };
    },
    resourceModifierRenderComponent: function(args){
        return {
            render: towerTickModifierRender,
            image: args['image'],
            priority: 11,
            key: args['key'],
            getTowerForTickModifierRender: resourceModifierGetTowerForTickModifierRender,
            renderState: "default"
        };
    },
    spendTimeCleverGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeCleverGoal)));
        return ecs.worldGoal(args);
    },
    makeComplimentSwarmGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeComplimentSwarmGoal)));
        return ecs.worldGoal(args);
    },
    joyMap: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.joyMap)));
        return ecs.emotionResourceMap(args);
    },
    entityPanel: function(args){
        args["size"] = (args["size"] === undefined) ? [550, 450] : args["size"];
        return {
            rendererComponents: [ecs.entityPanelRenderComponent(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            helpPanelComponent: ecs.helpPanelComponent(args),
            panelComponent: ecs.entityPanelComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    serializeComponent: function(args){
        if (args.serialize === undefined){ throw "ECS fail " + args.key + " missing serialize"; }
        if (args.postSerialize === undefined){ throw "ECS fail " + args.key + " missing postSerialize"; }
        return {
            serialize: args['serialize'],
            postSerialize: args['postSerialize']
        };
    },
    flirtationMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtationMineButton)));
        return ecs.resourceButton(args);
    },
    flashback_sadness: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_sadness)));
        return ecs.emotionResource(args);
    },
    acceptMeanlessGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.acceptMeanlessGoalConstruction)));
        return ecs.construction(args);
    },
    viceFlatYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.viceFlatYou)));
        return ecs.emotionSource(args);
    },
    deriveWorkTopicGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.deriveWorkTopicGoal)));
        return ecs.worldGoal(args);
    },
    becomeCriticalGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.becomeCriticalGoalConstruction)));
        return ecs.construction(args);
    },
    pathConnectRenderComponent: function(args){
        return {
            priority: 4,
            timeDrawn: 0,
            renderState: "default",
            render: pathConnectRender
        };
    },
    personCreateExec: function(args){
        return {
            execute: personCreateExec
        };
    },
    busyWorkTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.busyWorkTower)));
        return ecs.tower(args);
    },
    entityReplaceMarker: function(args){
        return {
            entitiesToMake: (args["entitiesToMake"] === undefined) ? [] : args["entitiesToMake"],
            skipFlag: (args["skipFlag"] === undefined) ? undefined : args["skipFlag"],
            getReplaceKeys: entityReplaceGetReplaceKeys
        };
    },
    stupidityMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.stupidityMed)));
        return ecs.creep(args);
    },
    workerRequestComponent: function(args){
        return {
            needsWorker: trueFunction,
            calculateWorkerTicks: calculateWorkerTicks,
            workerRequested: args.sourceTrait + '_worker',
            workersActive: [],
            workerCount: 1,
            workerLife: 20
        };
    },
    complimentYouGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentYouGoal)));
        return ecs.worldGoal(args);
    },
    anxiety: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.anxiety)));
        return ecs.currency(args);
    },
    project: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.project)));
        args["touchable"] = true;
        args["health"] = (args["health"] === undefined) ? 2000 : args["health"];
        args["panelKey"] = (args["panelKey"] === undefined) ? PARAMETERS.traitPanel : args["panelKey"];
        return {
            uiActionComponent: ecs.buildingUiActionComponent(args),
            experienceComponent: ecs.experienceComponent(args),
            createExecutables: [ecs.builtSourceCreateExec(args), ecs.makeExtraPathsExec(args)].concat([ecs.randomOpenPositionExec(args)]),
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            entityManagerComponent: ecs.entityManagerComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            isaacEntityComponent: ecs.isaacEntityComponent(args),
            rendererComponents: [ecs.builtSourceRendererComponent(args)],
            focusTickResponseComponent: (args.aliveEntities) ? ecs.focusTickAliveMakerComponent(args) : undefined,
            menuCloseComponent: ecs.traitMenuCloseComponent(args),
            personHeldComponent: (args.personHeld) ? ecs.personHeldComponent(args) : undefined,
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killExtensions(args)].concat([ecs.makeEntityComponent(args)]),
            healthComponent: ecs.healthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            positionComponent: ecs.positionComponent(args),
            mapSpawnComponent: ecs.builtSourceMapSpawnComponent(args),
            junctionComponent: ecs.junctionComponent(args),
            playerMadeComponent: ecs.fixedPlayerMadeComponent(args)
        };
    },
    risingTextRenderComponent: function(args){
        if (args.text === undefined){ throw "ECS fail " + args.key + " missing text"; }
        if (args.effectPos === undefined){ throw "ECS fail " + args.key + " missing effectPos"; }
        return {
            effectTime: 0.5,
            render: risingTextRender,
            text: args['text'],
            effectPos: args['effectPos'],
            height: 100,
            priority: 10,
            currentHeight: 0,
            renderState: "default"
        };
    },
    killFaithCrisis: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.killFaithCrisis)));
        return ecs.entityKill(args);
    },
    insecurityToCruelty: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecurityToCruelty)));
        return ecs.transformExec(args);
    },
    creepTickComponent: function(args){
        return {
            tick: creepTick,
            memoryChance: 0
        };
    },
    planSomethingFunGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.planSomethingFunGoal)));
        return ecs.worldGoal(args);
    },
    flashback_worthlessMedConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_worthlessMedConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    winMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.winMenu)));
        return ecs.goalCompleteMenu(args);
    },
    makeOldFailFlatButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeOldFailFlatButton)));
        return ecs.goalButton(args);
    },
    settingsPanel: function(args){
        args["draggable"] = false;
        args["key"] = PARAMETERS.settingsPanel;
        args["size"] = [450, 400];
        return {
            rendererComponents: [ecs.settingsPanelRenderComponent(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            panelComponent: ecs.panelComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    strength: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.strength)));
        return ecs.currency(args);
    },
    restLife_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.restLife_ext)));
        return ecs.sourceExtension(args);
    },
    social_warm: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.social_warm)));
        return ecs.currency(args);
    },
    pointCounterComponent: function(args){
        return {
            points: 0
        };
    },
    findUsefulButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findUsefulButton)));
        return ecs.goalButton(args);
    },
    currencyRequestedFocusPathStopComponent: function(args){
        return {
            currencyEntities: (args["currencyEntities"] === undefined) ? undefined : args["currencyEntities"],
            interactWithTrain: currencyRequestedInteractWithTrain,
            currencyEffect: (args["currencyEffect"] === undefined) ? undefined : args["currencyEffect"],
            currenciesNeededAtPoint: currencyRequestedCurrenciesNeededAtPoint,
            updateCurrencyDictWithStop: updateCurrencyDictWithStop,
            getCurrencyComponent: trueFunction,
            currenciesExistAtPoint: currenciesExistAtPoint,
            currenciesMadeAtPoint: (args["currenciesMadeAtPoint"] === undefined) ? emptyArrayFunction : args["currenciesMadeAtPoint"],
            isPathEnd: true,
            requiredOpinions: (args["requiredOpinions"] === undefined) ? [] : args["requiredOpinions"],
            percentComplete: currencyRequestedFocusPathStopPercentComplete,
            checkFocusStopDisabled: checkFocusStopDisabled,
            isDisabled: false,
            enableChecks: (args["enableChecks"] === undefined) ? [] : args["enableChecks"]
        };
    },
    trainPathTowerActiveRender: function(args){
        return {
            priority: 3,
            renderState: "default",
            render: trainPathTowerActiveRender
        };
    },
    findHelpGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findHelpGoalConstruction)));
        return ecs.construction(args);
    },
    himRelationButtonBranch: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.himRelationButtonBranch)));
        return ecs.flagBranch(args);
    },
    selfPathYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfPathYou)));
        return ecs.pathMaker(args);
    },
    talkAboutHimGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkAboutHimGoal)));
        return ecs.worldGoal(args);
    },
    memoryTowerButton: function(args){
        args["managerKey"] = args.sourceKey;
        args["multiTrait"] = true;
        args["subPanel"] = (args["subPanel"] === undefined) ? "Towers" : args["subPanel"];
        args["multiTrait"] = (args["multiTrait"] === undefined) ? false : args["multiTrait"];
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        return {
            healthComponent: ecs.singleHealthComponent(args),
            isaacEntityComponent: ecs.memoryTowerButtonIssacEntityComponent(args),
            uiActionComponent: ecs.buttonUiActionComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            buttonControlComponent: ecs.towerControlComponent(args),
            createExecutables: [ecs.markTraitNew(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            killExecutables: [ecs.killTowerButtonExec(args)],
            descriptionComponent: ecs.descriptionComponent(args),
            uniqueComponent: (args.timeToDeath === undefined && !args.multiTrait) ? ecs.uniqueComponent(args) : undefined,
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    experienceComponent: function(args){
        return {
            currentLevel: 1,
            updateExpansion: updateExpansion,
            xpPerLevel: 50,
            getXpLevel: getXpLevel,
            gainExp: gainExp,
            maxLevel: (args["maxLevel"] === undefined) ? PARAMETERS.maxExperience : args["maxLevel"]
        };
    },
    damageUpgradeCheck: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.damamgeUpgradeCheckExec(args)]
        };
    },
    forceOpennessGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.forceOpennessGoalConstruction)));
        return ecs.construction(args);
    },
    memoryFindPositionExec: function(args){
        if (args.startPos === undefined){ throw "ECS fail " + args.key + " missing startPos"; }
        return {
            execute: memoryFindPositionExec,
            startPos: args['startPos'],
            iterations: 25
        };
    },
    findLifeHelpMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findLifeHelpMenu)));
        return ecs.goalCompleteMenu(args);
    },
    toast: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.toast)));
        args["touchable"] = true;
        return {
            rendererComponents: [ecs.toastRenderComponent(args)],
            timedDeathComponent: ecs.timedDeathComponent(args),
            clickComponent: ecs.toastClickComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            notificationComponents: [ecs.toastNotificationComponent(args)]
        };
    },
    callousnessTowerPlaced: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.callousnessTowerPlaced)));
        return ecs.placedTower(args);
    },
    convinceActivityMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.convinceActivityMenu)));
        return ecs.goalCompleteMenu(args);
    },
    flirtTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtTower)));
        return ecs.tower(args);
    },
    dayPanel: function(args){
        return {
            panelComponent: ecs.setPanelComponent(args),
            absolutePositionComponent: ecs.dayPanelAbsolutePositionComponent(args),
            rendererComponents: [ecs.dayPanelRenderComponent(args)],
            uiClickComponent: ecs.panelUiClickComponent(args)
        };
    },
    panelComponent: function(args){
        return {
            panelButtons: [],
            expandPanel: expandPanel,
            minimized: true,
            canClose: true,
            closed: true,
            ignoreWhenMinimized: true
        };
    },
    tiredSwarmHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tiredSwarmHim)));
        return ecs.instantEmotionResource(args);
    },
    reachOutMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reachOutMenu)));
        return ecs.goalCompleteMenu(args);
    },
    complimentSwarmYouMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentSwarmYouMine)));
        return ecs.emotionResource(args);
    },
    steamAchievementNotificationComponent: function(args){
        return {
            notificationFunctions: simpleDict(PARAMETERS.goalComplete, checkSteamAchievement),
            serializeComponent: ecs.notificationSerializeComponent(args)
        };
    },
    helpfulToInsecurity: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpfulToInsecurity)));
        return ecs.transformExec(args);
    },
    learnHistoryGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.learnHistoryGoal)));
        return ecs.worldGoal(args);
    },
    disableMemoriesComponent: function(args){
        return {
            disableNewMemories: true,
            checkTraitDisabled: checkMemoriesDisabled
        };
    },
    criticismSwarmYouMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismSwarmYouMine)));
        return ecs.emotionResource(args);
    },
    slowWorkFlat: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.slowWorkFlat)));
        return ecs.instantEmotionResource(args);
    },
    difficultySettingComponent: function(args){
        return {
            difficulty: 0
        };
    },
    worthlessMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worthlessMed)));
        return ecs.creep(args);
    },
    pushInsecurityMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.pushInsecurityMenu)));
        return ecs.goalCompleteMenu(args);
    },
    explainFindHelpFail: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.explainFindHelpFail)));
        return ecs.menuModifier(args);
    },
    goodnessMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goodnessMine)));
        return ecs.resource(args);
    },
    relationBranch: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.relationBranch)));
        return ecs.flagBranch(args);
    },
    friendMeditateAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.friendMeditateAction)));
        return ecs.currencyAction(args);
    },
    soberDownGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.soberDownGoal)));
        return ecs.worldGoal(args);
    },
    guiltGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.guiltGoal)));
        return ecs.worldGoal(args);
    },
    menuTutorialTextComponent: function(args){
        return {
            entityToMark: args['entityToMark'],
            tutorialDone: menuTutorialDone,
            checkTutorialUiKey: checkTutorialUiKey,
            nextEntities: (args["nextEntities"] === undefined) ? undefined : args["nextEntities"]
        };
    },
    helpful_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpful_ext)));
        return ecs.sourceExtension(args);
    },
    needWorkMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needWorkMenu)));
        return ecs.goalCompleteMenu(args);
    },
    funPathRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.funPathRelationship)));
        return ecs.pathMaker(args);
    },
    chkForPlayerInterrupt: function(args){
        return {
            execute: chkForPlayerInterruptExec,
            playerExecute: ecs.makeParticleEffect(args)
        };
    },
    resentYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.resentYou)));
        return ecs.emotionSource(args);
    },
    joyBurstMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.joyBurstMine)));
        return ecs.emotionResource(args);
    },
    support_you: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.support_you)));
        return ecs.currency(args);
    },
    overcomeCrisisGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.overcomeCrisisGoalConstruction)));
        return ecs.construction(args);
    },
    findHelpMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findHelpMenu)));
        return ecs.goalCompleteMenu(args);
    },
    accuseSelfishGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.accuseSelfishGoal)));
        return ecs.worldGoal(args);
    },
    openMenuMarker: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            rendererComponents: [ecs.openMenuMarkerRenderComponent(args)],
            openMenuMarkerComponent: ecs.openMenuMarkerComponent(args)
        };
    },
    calmnessMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmnessMine)));
        return ecs.resource(args);
    },
    autosaver: function(args){
        return {
            tickComponent: ecs.autosaveTickComponent(args)
        };
    },
    flashback_complimentMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_complimentMed)));
        return ecs.emotionResource(args);
    },
    settingsPanelRenderComponent: function(args){
        return {
            sfxVolFunctions: undefined,
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            drawPanelButton: drawPanelButton,
            quitFunction: undefined,
            renderState: "default",
            insetColor: "#000000",
            difficultyFunctions: undefined,
            priority: 18,
            snapPanelPos: snapPanelPos,
            soundVolFunctions: undefined,
            textColor: "#000000",
            backImage: "uiBack",
            drawImageButton: drawImageButton,
            render: outPanelRender,
            specificRender: settingsPanelRender,
            soundFunction: undefined,
            renderTime: 0,
            drawHelpButton: drawHelpButton,
            animatingTime: 0.1,
            fullscreenFunction: undefined,
            sfxFunction: undefined
        };
    },
    autosaveNotificationComponent: function(args){
        return {
            notificationFunctions: simpleDict(PARAMETERS.goalComplete, autosaveOnGoalComplete),
            serializeComponent: ecs.notificationSerializeComponent(args)
        };
    },
    pushAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.pushAction)));
        return ecs.currencyAction(args);
    },
    talkAboutHimButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkAboutHimButton)));
        return ecs.goalButton(args);
    },
    helpValueButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpValueButton)));
        return ecs.towerButton(args);
    },
    interestingEmo: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.interestingEmo)));
        return ecs.splitReplace(args);
    },
    makeComplimentFlatMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeComplimentFlatMenu)));
        return ecs.goalCompleteMenu(args);
    },
    entityReplace: function(args){
        return {
            replaceMarker: ecs.entityReplaceMarker(args)
        };
    },
    learnHimMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.learnHimMenu)));
        return ecs.goalCompleteMenu(args);
    },
    flirtResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtResult)));
        return ecs.randomReplace(args);
    },
    entityPanelRenderComponent: function(args){
        if (args.entityImage === undefined){ throw "ECS fail " + args.key + " missing entityImage"; }
        return {
            drawImageButton: drawImageButton,
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "uiBack",
            entityImage: args['entityImage'],
            insetColor: "#000000",
            animatingTime: 0.1,
            priority: 18,
            render: outPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            specificRender: entityPanelRender,
            drawHelpButton: drawHelpButton
        };
    },
    supportTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportTower)));
        return ecs.memoryTower(args);
    },
    singleHealthComponent: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.singleHealthComponent)));
        return {
            kill: killHealthComponent,
            damageFactor: (args["damageFactor"] === undefined) ? 1 : args["damageFactor"],
            health: args['health'],
            maxHealth: args['health']
        };
    },
    sharePainButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sharePainButton)));
        return ecs.goalButton(args);
    },
    findLifeHelpResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findLifeHelpResult)));
        return ecs.randomReplace(args);
    },
    oldFailMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldFailMineConstruction)));
        return ecs.construction(args);
    },
    pauseComponent: function(args){
        return {
            paused: true
        };
    },
    feelUselessMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.feelUselessMenu)));
        return ecs.goalCompleteMenu(args);
    },
    opinionTickComponent: function(args){
        return {
            emotionsToMake: (args["emotionsToMake"] === undefined) ? undefined : args["emotionsToMake"],
            tick: opinionTick,
            impulseTicks: (args["impulseTicks"] === undefined) ? 30 : args["impulseTicks"],
            ticks: 0
        };
    },
    featureItemActionExec: function(args){
        if (args.execCurrencyKey === undefined){ throw "ECS fail " + args.key + " missing execCurrencyKey"; }
        if (args.execCurrencyChange === undefined){ throw "ECS fail " + args.key + " missing execCurrencyChange"; }
        return {
            execCurrencyChange: args['execCurrencyChange'],
            execute: featureItemActionExec,
            execCurrencyKey: args['execCurrencyKey']
        };
    },
    fascinateButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.fascinateButton)));
        return ecs.goalButton(args);
    },
    obsessionsButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessionsButton)));
        return ecs.towerButton(args);
    },
    starParticleEffectRenderComponent: function(args){
        if (args.effectPos === undefined){ throw "ECS fail " + args.key + " missing effectPos"; }
        return {
            priority: 14,
            render: starParticleEffectRender,
            image: "star",
            effectPos: args['effectPos'],
            timeDrawn: 0,
            scaleTime: 0.15,
            renderState: "default"
        };
    },
    viceButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.viceButton)));
        return ecs.towerButton(args);
    },
    duplicatePathExec: function(args){
        return {
            execute: duplicatePathExec
        };
    },
    memory_oldLife: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_oldLife)));
        return ecs.memory(args);
    },
    complimentSwarmYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentSwarmYou)));
        return ecs.emotionSource(args);
    },
    relationshipMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.relationshipMineConstruction)));
        return ecs.construction(args);
    },
    cleverResponseMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.cleverResponseMenu)));
        return ecs.goalCompleteMenu(args);
    },
    flashback_aloneMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_aloneMed)));
        return ecs.emotionResource(args);
    },
    himEntities: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.himEntities)));
        return ecs.entityReplace(args);
    },
    learnHimGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.learnHimGoal)));
        return ecs.worldGoal(args);
    },
    timedDeathRenderComponent: function(args){
        return {
            priority: 7,
            renderState: "default",
            render: timedDeathRender
        };
    },
    acceptMeanlessButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.acceptMeanlessButton)));
        return ecs.goalButton(args);
    },
    oldHurtMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldHurtMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    buttonManageComponent: function(args){
        return {
            renderButton: renderButton,
            panelButtons: [],
            lineHeight: (args["lineHeight"] === undefined) ? 16 : args["lineHeight"]
        };
    },
    dailyEntityMaker: function(args){
        return {
            dailyEntityMakerComponent: ecs.dailyEntityMakerComponent(args),
            createExecutables: [ecs.randomOpenPositionExec(args)],
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            dayResponseComponent: ecs.dailyEntityDayResponseComponent(args),
            playerMadeComponent: ecs.fixedPlayerMadeComponent(args)
        };
    },
    hisWorkToHisBadWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisWorkToHisBadWork)));
        return ecs.transformExec(args);
    },
    creepComponent: function(args){
        if (args.emotion === undefined){ throw "ECS fail " + args.key + " missing emotion"; }
        return {
            emotion: args['emotion'],
            towerModifier: (args["towerModifier"] === undefined) ? args['undefined'] : args["towerModifier"],
            selfDamage: PARAMETERS.creepSelfDamage
        };
    },
    insecureMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecureMenu)));
        return ecs.goalCompleteMenu(args);
    },
    tutorialUnpauseRenderComponent: function(args){
        if (args.text === undefined){ throw "ECS fail " + args.key + " missing text"; }
        if (args.yStart === undefined){ throw "ECS fail " + args.key + " missing yStart"; }
        return {
            priority: 24,
            text: args['text'],
            renderState: "default",
            yStart: args['yStart'],
            render: tutorialUnpauseRender
        };
    },
    oldLifeMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldLifeMine)));
        return ecs.emotionResource(args);
    },
    killTrain: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.killTrainExec(args), ecs.killEntity(args)]
        };
    },
    opinionConditionalExec: function(args){
        if (args.person === undefined){ throw "ECS fail " + args.key + " missing person"; }
        if (args.opinions === undefined){ throw "ECS fail " + args.key + " missing opinions"; }
        if (args.entitiesToMake === undefined){ throw "ECS fail " + args.key + " missing entitiesToMake"; }
        return {
            sourceId: (args["sourceId"] === undefined) ? undefined : args["sourceId"],
            person: args['person'],
            execute: opinionConditional,
            entitiesToMake: args['entitiesToMake'],
            opinions: args['opinions']
        };
    },
    killTrait: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.killTraitExec(args), ecs.killEntity(args)]
        };
    },
    needPainTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needPainTower)));
        return ecs.memoryTower(args);
    },
    flirtTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtTowerConstruction)));
        return ecs.construction(args);
    },
    pathMaker: function(args){
        return {
            replaceMarker: ecs.pathMakerReplaceMarker(args)
        };
    },
    opinionComponent: function(args){
        return {
            successOpinions: (args["successOpinions"] === undefined) ? {} : args["successOpinions"]
        };
    },
    needPainAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needPainAction)));
        return ecs.currencyAction(args);
    },
    spellRenderComponent: function(args){
        return {
            priority: 9,
            renderState: "default",
            render: spellRender
        };
    },
    pushTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.pushTowerConstruction)));
        return ecs.construction(args);
    },
    workTopicDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.workTopicDeposit)));
        return ecs.deposit(args);
    },
    goalCompleteMenuComponent: function(args){
        return {
            path: []
        };
    },
    socialTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialTowerConstruction)));
        return ecs.construction(args);
    },
    supportCrisisGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportCrisisGoalConstruction)));
        return ecs.construction(args);
    },
    makeStupidityFlatMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeStupidityFlatMenu)));
        return ecs.goalCompleteMenu(args);
    },
    identityComponent: function(args){
        if (args.key === undefined){ throw "ECS fail " + args.key + " missing key"; }
        if (args.uid === undefined){ throw "ECS fail " + args.key + " missing uid"; }
        return {
            uid: args['uid'],
            tags: (args["tags"] === undefined) ? [] : args["tags"],
            sourceId: (args["sourceId"] === undefined) ? undefined : args["sourceId"],
            image: (args["image"] === undefined) ? undefined : args["image"],
            sourceName: (args["sourceName"] === undefined) ? undefined : args["sourceName"],
            key: args['key'],
            touchable: (args["touchable"] === undefined) ? false : args["touchable"],
            name: (args["name"] === undefined) ? undefined : args["name"]
        };
    },
    him_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.him_ext)));
        return ecs.sourceExtension(args);
    },
    cleverResponseGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.cleverResponseGoal)));
        return ecs.worldGoal(args);
    },
    rendererSystemComponent: function(args){
        return {
            currentRenderState: "default"
        };
    },
    flashback_angerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_angerConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    appreciateWorkButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.appreciateWorkButton)));
        return ecs.goalButton(args);
    },
    casualSwarmYouMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.casualSwarmYouMine)));
        return ecs.emotionResource(args);
    },
    goodPathClever: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goodPathClever)));
        return ecs.pathMaker(args);
    },
    flipGood: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flipGood)));
        return ecs.pairTransform(args);
    },
    rebuildMenuComponent: function(args){
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        return {
            getRebuildButton: getRebuildButton,
            rebuildFunction: undefined,
            getRebuildFunction: getRebuildFunction,
            sourceKey: args['sourceKey']
        };
    },
    insecureGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecureGoal)));
        return ecs.worldGoal(args);
    },
    sharePainMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sharePainMenu)));
        return ecs.goalCompleteMenu(args);
    },
    createModifyComponent: function(args){
        return {
            createModifiers: (args["createModifiers"] === undefined) ? {} : args["createModifiers"]
        };
    },
    probeTopicGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.probeTopicGoal)));
        return ecs.worldGoal(args);
    },
    allBuildingPanelRenderComponent: function(args){
        return {
            insetColor: "#000000",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "uiBack",
            renderTime: 0,
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            pageDownFunction: undefined,
            priority: 18,
            render: outPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            setCategoryFn: {},
            pageUpFunction: undefined,
            currentCategory: undefined,
            buttonGroupCount: 1,
            textColor: "#000000",
            renderState: "default",
            page: 1,
            specificRender: allBuildingPanelRender,
            drawHelpButton: drawHelpButton
        };
    },
    defineHelpMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.defineHelpMenu)));
        return ecs.goalCompleteMenu(args);
    },
    notificationCurrencyComponent: function(args){
        if (args.notificationCurrency === undefined){ throw "ECS fail " + args.key + " missing notificationCurrency"; }
        if (args.currencyName === undefined){ throw "ECS fail " + args.key + " missing currencyName"; }
        return {
            notificationCurrency: args['notificationCurrency'],
            currencyName: args['currencyName']
        };
    },
    killStartRelationYouButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.killStartRelationYouButton)));
        return ecs.entityKill(args);
    },
    connectSourceReplaceMarker: function(args){
        if (args.sourceId === undefined){ throw "ECS fail " + args.key + " missing sourceId"; }
        return {
            sourceId: args['sourceId'],
            getReplaceKeys: connectSourceGetReplaceKeys
        };
    },
    mistrustJoyButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.mistrustJoyButton)));
        return ecs.towerButton(args);
    },
    noFocusNotifierRenderComponent: function(args){
        return {
            priority: 16,
            render: noFocusNotifierRender
        };
    },
    creep: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.creep)));
        return {
            pathVelocityComponent: ecs.pathVelocityComponent(args),
            rendererComponents: [ecs.creepRenderComponent(args), ecs.hitRenderComponent(args)],
            damageableComponent: ecs.damageableComponent(args),
            creepComponent: ecs.creepComponent(args),
            createExecutables: [ecs.creepCreateExec(args)],
            killExecutables: [ecs.creepDeathExec(args)],
            tickComponent: ecs.creepTickComponent(args),
            healthComponent: ecs.healthComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            dayResponseComponent: ecs.currencyDayResponseComponent(args),
            loseControlExec: ecs.killEntity(args)
        };
    },
    isaacEntityComponent: function(args){
        return {
            endLifecycle: endLifecycle,
            startLifecycle: makeIsaacLifecycleEntities,
            makeLifecycleEntities: makeLifecycleEntities,
            entitiesMade: [],
            isaacEntities: (args["isaacEntities"] === undefined) ? [] : args["isaacEntities"]
        };
    },
    selfExtension: function(args){
        return {
            rendererComponents: [ecs.selfExtensionRender(args)],
            sourceExtensionComponent: ecs.sourceExtensionComponent(args),
            selfExtensionComponent: ecs.selfExtensionComponent(args),
            tickComponent: ecs.selfExtensionTickComponent(args),
            positionComponent: ecs.positionComponent(args)
        };
    },
    selfish_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfish_ext)));
        return ecs.sourceExtension(args);
    },
    notification: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            notifyComponent: ecs.notifyComponent(args)
        };
    },
    memoryFadeComponent: function(args){
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        return {
            sourceKey: args['sourceKey']
        };
    },
    switchYouInfoDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.switchYouInfoDeposit)));
        return ecs.switch(args);
    },
    tickComponent: function(args){
        return {
            tick: (args["tick"] === undefined) ? args['trueFunction'] : args["tick"]
        };
    },
    panelRenderComponent: function(args){
        if (args.specificRender === undefined){ throw "ECS fail " + args.key + " missing specificRender"; }
        return {
            insetColor: "#000000",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "uiBack",
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            priority: 18,
            render: outPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            specificRender: args['specificRender'],
            drawHelpButton: drawHelpButton
        };
    },
    cheerMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.cheerMine)));
        return ecs.memoryResource(args);
    },
    tryNewGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryNewGoalConstruction)));
        return ecs.construction(args);
    },
    you_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.you_ext)));
        return ecs.sourceExtension(args);
    },
    connectFriendsGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.connectFriendsGoal)));
        return ecs.worldGoal(args);
    },
    playerTriggeredNotification: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.IdentityComponent(args),
            notifyComponent: ecs.notifyComponent(args)
        };
    },
    tutorialTextComponent: function(args){
        if (args.entityToMark === undefined){ throw "ECS fail " + args.key + " missing entityToMark"; }
        return {
            entityToMark: args['entityToMark'],
            tutorialDone: tutorialTextTutorialDone,
            checkTutorialUiKey: checkTutorialUiKey,
            nextEntities: (args["nextEntities"] === undefined) ? undefined : args["nextEntities"]
        };
    },
    aloneSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.aloneSmall)));
        return ecs.creep(args);
    },
    insecurityPathNewRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecurityPathNewRelationship)));
        return ecs.pathMaker(args);
    },
    notifyEntityMaker: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            notificationComponents: [ecs.notifyEntityMakerNotificationComponent(args)]
        };
    },
    defineRoleReplaceMarker: function(args){
        if (args.possiblePairs === undefined){ throw "ECS fail " + args.key + " missing possiblePairs"; }
        if (args.exhaustEntities === undefined){ throw "ECS fail " + args.key + " missing exhaustEntities"; }
        return {
            exhaustEntities: args['exhaustEntities'],
            possiblePairs: args['possiblePairs'],
            getReplaceKeys: defineRoleGetReplaceKeys
        };
    },
    needBusyTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needBusyTower)));
        return ecs.tower(args);
    },
    fascinateMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.fascinateMenu)));
        return ecs.goalCompleteMenu(args);
    },
    obsessionsTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessionsTowerConstruction)));
        return ecs.construction(args);
    },
    utilityPanelAbsolutePositionComponent: function(args){
        return {
            y: 678,
            x: 600,
            size: [250, 90]
        };
    },
    overcomeCrisisMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.overcomeCrisisMenu)));
        return ecs.goalCompleteMenu(args);
    },
    worker: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worker)));
        args["tags"] = (args.tags) ? args.tags.concat([args.key]) : [args.key];
        return {
            pathVelocityComponent: ecs.pathVelocityComponent(args),
            rendererComponents: [ecs.workerRenderComponent(args)],
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            dayResponseComponent: (args.checkDayEnd) ? ecs.currencyDayResponseComponent(args) : undefined
        };
    },
    menuModifierComponent: function(args){
        return {
            completeText: (args["completeText"] === undefined) ? undefined : args["completeText"],
            name: (args["name"] === undefined) ? undefined : args["name"]
        };
    },
    socialWarmMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialWarmMineConstruction)));
        return ecs.construction(args);
    },
    support: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.support)));
        return ecs.currency(args);
    },
    healthModifyComponent: function(args){
        return {
            idleHealthChange: -10,
            activeHealthChange: 30,
            activated: false,
            healthModifyAmount: healthModifyAmount
        };
    },
    personalityComponent: function(args){
        args["knownPersonalityTraits"] = (args["knownPersonalityTraits"] === undefined) ? [] : args["knownPersonalityTraits"];
        args["unknownPersonalityTraits"] = (args["unknownPersonalityTraits"] === undefined) ? [] : args["unknownPersonalityTraits"];
        if (args.knownPersonalityTraits === undefined){ throw "ECS fail " + args.key + " missing knownPersonalityTraits"; }
        return {
            knownPersonalityTraits: args['knownPersonalityTraits'],
            heldOpinions: (args["heldOpinions"] === undefined) ? PARAMETERS.defaultHeldOpinions : args["heldOpinions"],
            getAll: getAllPersonality,
            addOpinionToPersonality: addOpinionToPersonality,
            personHistory: [],
            personalityTraits: args.unknownPersonalityTraits.concat(args.knownPersonalityTraits)
        };
    },
    helpValueAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpValueAction)));
        return ecs.currencyAction(args);
    },
    dayKillExec: function(args){
        return {
            execute: dayKillExec
        };
    },
    criticismSwarmYouMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismSwarmYouMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    traitHelpInfoPanel: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.traitHelpInfoPanel)));
        return ecs.helpInfoPanel(args);
    },
    trainPathMakerComponent: function(args){
        return {
            addTrainStop: addTrainStop,
            removeTrainStop: removeTrainStop,
            stops: [],
            checkTrainStop: checkTrainStop,
            memoizedCurrenciesNeeded: undefined,
            trainPathKey: PARAMETERS.trainPath,
            makeTrainPath: makeTrainPath,
            getPathCurrenciesNeeded: getPathCurrenciesNeeded
        };
    },
    memory_oldHurt: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_oldHurt)));
        return ecs.memory(args);
    },
    makeAll: function(args){
        return {
            replaceMarker: ecs.makeAllReplaceMarker(args)
        };
    },
    makeRandomMultipleReplaceMarker: function(args){
        if (args.count === undefined){ throw "ECS fail " + args.key + " missing count"; }
        if (args.entitiesToMake === undefined){ throw "ECS fail " + args.key + " missing entitiesToMake"; }
        return {
            count: args['count'],
            minCount: (args["minCount"] === undefined) ? 1 : args["minCount"],
            entitiesToMake: args['entitiesToMake'],
            getReplaceKeys: makeRandomMultipleGetReplaceKeys
        };
    },
    guiltButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.guiltButton)));
        return ecs.goalButton(args);
    },
    depositFocusPathStopComponent: function(args){
        return {
            interactWithTrain: depositInteractWithTrain,
            currenciesNeededAtPoint: (args["currenciesNeededAtPoint"] === undefined) ? emptyArrayFunction : args["currenciesNeededAtPoint"],
            currenciesMadeAtPoint: depositCurrenciesMadeAtPoint,
            isDisabled: false,
            currenciesExistAtPoint: currenciesExistAtPoint,
            updateCurrencyDictWithStop: updateCurrencyDictWithStop,
            isPathEnd: (args["isPathEnd"] === undefined) ? false : args["isPathEnd"],
            checkFocusStopDisabled: checkFocusStopDisabled,
            requiredOpinions: (args["requiredOpinions"] === undefined) ? [] : args["requiredOpinions"],
            enableChecks: (args["enableChecks"] === undefined) ? [] : args["enableChecks"]
        };
    },
    distractAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.distractAction)));
        return ecs.currencyAction(args);
    },
    endGoal: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.endGoalExec(args), ecs.killEntity(args)]
        };
    },
    speakOfValueMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.speakOfValueMenu)));
        return ecs.goalCompleteMenu(args);
    },
    personTower: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        args["isPathEnd"] = (args["isPathEnd"] === undefined) ? (args.damageMultipliers ? true : false) : args["isPathEnd"];
        args["tags"] = (args["tags"] === undefined) ? [args.key] : args["tags"];
        return {
            focusPathStopComponent: ecs.towerFocusPathStopComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args), ecs.damageRenderComponent(args)],
            focusTickResponseComponent: ecs.towerFocusTickResponseComponent(args),
            healthModifyComponent: ecs.healthModifyComponent(args),
            personHeldComponent: ecs.personHeldComponent(args),
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            damageComponent: (args.damageMultipliers) ? ecs.damageComponent(args) : undefined,
            managedComponent: ecs.managedComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)].concat([ecs.towerCreateExec(args)]),
            junctionComponent: ecs.junctionComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            tickComponent: ecs.towerTickComponent(args),
            towerComponent: ecs.towerComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    switchTriggerCrisisButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.switchTriggerCrisisButton)));
        return ecs.switch(args);
    },
    guiltFlatYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.guiltFlatYou)));
        return ecs.emotionSource(args);
    },
    trainPathMakingPanel: function(args){
        args["y"] = 5;
        args["x"] = width - 355;
        args["key"] = PARAMETERS.trainPathMakingPanel;
        args["size"] = [350, 300];
        return {
            rendererComponents: [ecs.trainPathMakingPanelRender(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            panelComponent: ecs.panelComponent(args),
            pauseComponent: ecs.pauseComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    completeWorkResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.completeWorkResult)));
        return ecs.randomReplace(args);
    },
    busyWorkDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.busyWorkDeposit)));
        return ecs.deposit(args);
    },
    hisGraciousMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisGraciousMenu)));
        return ecs.goalCompleteMenu(args);
    },
    worldGoalParticleEffectLifeSentinelComponent: function(args){
        if (args.sourceId === undefined){ throw "ECS fail " + args.key + " missing sourceId"; }
        return {
            sourceId: args['sourceId'],
            checkAlive: checkWorldGoalParticleEffectAlive
        };
    },
    flashback_casualSmallConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_casualSmallConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    switchFeedCrisisButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.switchFeedCrisisButton)));
        return ecs.switch(args);
    },
    trainRenderComponent: function(args){
        if (args.trainColor === undefined){ throw "ECS fail " + args.key + " missing trainColor"; }
        return {
            priority: 11,
            render: trainRender,
            linePos: false,
            timeDrawn: 0,
            previousPositions: [],
            renderState: "default",
            trainColor: args['trainColor']
        };
    },
    beSupportedGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.beSupportedGoal)));
        return ecs.worldGoal(args);
    },
    managedComponent: function(args){
        if (args.sourceTrait === undefined){ throw "ECS fail " + args.key + " missing sourceTrait"; }
        return {
            managerKey: args['sourceTrait'],
            addExperienceToManager: addExperienceToManager,
            killOnTransform: (args["killOnTransform"] === undefined) ? false : args["killOnTransform"],
            isManagingEntity: isManagingEntity
        };
    },
    role: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.role)));
        return ecs.defineRole(args);
    },
    busyWorkMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.busyWorkMine)));
        return ecs.resource(args);
    },
    memoryGoalTrackComponent: function(args){
        return {
            successExecutables: [ecs.goalCompleteExec(args)].concat([ecs.trackActionables(args), ecs.makeEntityComponent(args), ecs.makeGoalMenuExecutable(args)]).concat([ecs.memoryGoalCompleteExec(args)]),
            checkCompleted: checkWorldGoalComponent
        };
    },
    wobbleRendererComponent: function(args){
        return {
            wobble: 0,
            getWobble: getWobble
        };
    },
    appreciateWorkGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.appreciateWorkGoalConstruction)));
        return ecs.construction(args);
    },
    makeSlowWorkSwarmGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeSlowWorkSwarmGoalConstruction)));
        return ecs.construction(args);
    },
    focusComponent: function(args){
        return {
            focusMax: 100,
            focusUsed: 0
        };
    },
    bullet: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            rendererComponents: [ecs.bulletRenderComponent(args)],
            tickComponent: ecs.bulletTickComponent(args)
        };
    },
    willMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.willMineConstruction)));
        return ecs.construction(args);
    },
    resourceModifierComponent: function(args){
        if (args.stopResources === undefined){ throw "ECS fail " + args.key + " missing stopResources"; }
        if (args.doubleResources === undefined){ throw "ECS fail " + args.key + " missing doubleResources"; }
        if (args.towerId === undefined){ throw "ECS fail " + args.key + " missing towerId"; }
        return {
            doubleResources: args['doubleResources'],
            stopResources: args['stopResources'],
            towerId: args['towerId']
        };
    },
    push: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.push)));
        return ecs.currency(args);
    },
    disableMemoriesTickComponent: function(args){
        if (args.name === undefined){ throw "ECS fail " + args.key + " missing name"; }
        return {
            tick: disableMemoriesTick,
            name: args['name']
        };
    },
    memory_joyBurst: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_joyBurst)));
        return ecs.memory(args);
    },
    sympathyAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sympathyAction)));
        return ecs.currencyAction(args);
    },
    randomCarousel: function(args){
        return {
            animationTime: 3,
            flatDisplayStartTime: undefined,
            carousel: undefined,
            render: randomCarouselRender,
            goodImage: "randomGoodImage",
            frameImage: "frame",
            badImage: "randomBadImage",
            goodResult: undefined,
            setMarker: randomCarouselSetMarker,
            imgSize: [100, 100],
            animationDone: false
        };
    },
    casualSwarmYouMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.casualSwarmYouMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    himSupportGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.himSupportGoal)));
        return ecs.worldGoal(args);
    },
    friendMeditateTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.friendMeditateTower)));
        return ecs.tower(args);
    },
    stateComponent: function(args){
        return {
            paused: false,
            playerControlled: false
        };
    },
    restlessPathNewRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.restlessPathNewRelationship)));
        return ecs.pathMaker(args);
    },
    makeIfMissing: function(args){
        return {
            createExecutables: [ecs.makeIfMissingExec(args), ecs.killEntity(args)]
        };
    },
    diveHurtMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.diveHurtMenu)));
        return ecs.goalCompleteMenu(args);
    },
    nullEntity: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.killEntity(args)]
        };
    },
    selfDamageEffectRenderComponent: function(args){
        return {
            priority: 19,
            timeDrawn: 0,
            renderState: "default",
            animationTime: 0.3,
            render: selfDamageEffectRender
        };
    },
    makeCriticismSwarmGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeCriticismSwarmGoal)));
        return ecs.worldGoal(args);
    },
    trainKillExec: function(args){
        return {
            execute: trainKillExec
        };
    },
    jealousyBurst: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.jealousyBurst)));
        return ecs.emotionSource(args);
    },
    startConverseGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startConverseGoal)));
        return ecs.worldGoal(args);
    },
    talkAboutYouGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkAboutYouGoalConstruction)));
        return ecs.construction(args);
    },
    funPathHurting: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.funPathHurting)));
        return ecs.pathMaker(args);
    },
    complimentYouButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentYouButton)));
        return ecs.goalButton(args);
    },
    allCurrencyRenderClear: function(args){
        return {
            priority: 1,
            renderState: "default",
            render: allCurrencyRenderClear
        };
    },
    gameEndRenderComponent: function(args){
        return {
            priority: 24,
            renderState: "default",
            render: gameEndRender
        };
    },
    goalHelpInfoPanel: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goalHelpInfoPanel)));
        return ecs.helpInfoPanel(args);
    },
    oldFailMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldFailMine)));
        return ecs.resource(args);
    },
    flirtationMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtationMine)));
        return ecs.resource(args);
    },
    noticeThingGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.noticeThingGoal)));
        return ecs.worldGoal(args);
    },
    explainFeedCrisisFail: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.explainFeedCrisisFail)));
        return ecs.menuModifier(args);
    },
    closestOpenPositionExec: function(args){
        if (args.startPos === undefined){ throw "ECS fail " + args.key + " missing startPos"; }
        return {
            execute: closestOpenPositionExec,
            startPos: args['startPos']
        };
    },
    anxietyMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.anxietyMineButton)));
        return ecs.resourceButton(args);
    },
    trainComponent: function(args){
        return {
            getCurrenciesHeld: getCurrenciesHeld,
            carriage: undefined,
            calculateTrainCurrencies: calculateTrainCurrencies,
            lastDrawPos: [0, 0],
            getCurrentCarriage: getCurrentCarriage
        };
    },
    choreMaker: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.choreMaker)));
        return ecs.dailyEntityMaker(args);
    },
    goalTrackComponent: function(args){
        if (args.checkCompleted === undefined){ throw "ECS fail " + args.key + " missing checkCompleted"; }
        return {
            successExecutables: [ecs.goalCompleteExec(args)],
            checkCompleted: args['checkCompleted']
        };
    },
    makeCriticismSwarmGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeCriticismSwarmGoalConstruction)));
        return ecs.construction(args);
    },
    lostControlDeathExec: function(args){
        return {
            execute: lostControlDeathExec
        };
    },
    keyPressComponent: function(args){
        if (args.handleKeyPress === undefined){ throw "ECS fail " + args.key + " missing handleKeyPress"; }
        return {
            handleKeyPress: args['handleKeyPress']
        };
    },
    tryForConnectionYouMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryForConnectionYouMenu)));
        return ecs.goalCompleteMenu(args);
    },
    resentYouMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.resentYouMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    niceGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.niceGoal)));
        return ecs.worldGoal(args);
    },
    openUpGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.openUpGoal)));
        return ecs.worldGoal(args);
    },
    buildingConnectExec: function(args){
        return {
            execute: buildingConnectExec,
            startEntityKey: (args["startEntityKey"] === undefined) ? undefined : args["startEntityKey"]
        };
    },
    boost: function(args){
        return {
            identityComponent: ecs.identityComponent(args),
            rendererComponents: [ecs.boostRenderComponent(args)],
            boostSlotComponent: ecs.boostSlotComponent(args),
            createExecutables: [ecs.randomOpenPositionExec(args)],
            positionComponent: ecs.positionComponent(args)
        };
    },
    shameBurstMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.shameBurstMine)));
        return ecs.emotionResource(args);
    },
    newRelationship_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.newRelationship_ext)));
        return ecs.sourceExtension(args);
    },
    boostSlotComponent: function(args){
        if (args.traits === undefined){ throw "ECS fail " + args.key + " missing traits"; }
        return {
            traits: args['traits'],
            checkEntityForBoost: checkEntityForBoost
        };
    },
    tickEmotionComponent: function(args){
        if (args.currency === undefined){ throw "ECS fail " + args.key + " missing currency"; }
        return {
            currency: args['currency'],
            checkTickContinue: checkTickContinue,
            traits: (args["traits"] === undefined) ? [] : args["traits"]
        };
    },
    tryForConnectionHimGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryForConnectionHimGoalConstruction)));
        return ecs.construction(args);
    },
    autoPathReplaceMarker: function(args){
        return {
            getReplaceKeys: autoPathGetReplaceKeys
        };
    },
    checkMakeDeposit: function(args){
        return {
            execute: checkMakeDeposit,
            checkMakeDeposit: (args["checkMakeDeposit"] === undefined) ? true : args["checkMakeDeposit"]
        };
    },
    largeValueDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.largeValueDeposit)));
        return ecs.deposit(args);
    },
    becomeCriticalButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.becomeCriticalButton)));
        return ecs.goalButton(args);
    },
    playerMadeComponent: function(args){
        return {
            playerKillable: (args["playerKillable"] === undefined) ? true : args["playerKillable"],
            canExpandInto: (args["canExpandInto"] === undefined) ? true : args["canExpandInto"]
        };
    },
    defineHelpButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.defineHelpButton)));
        return ecs.goalButton(args);
    },
    flashback_oldFailMedConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_oldFailMedConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    expandTrait: function(args){
        return {
            maxExpansion: 9,
            execute: expandTraitExec,
            traitToExpand: "hisWork"
        };
    },
    constructionTickComponent: function(args){
        return {
            tick: constructionTick
        };
    },
    lifeSentinelComponent: function(args){
        if (args.checkAlive === undefined){ throw "ECS fail " + args.key + " missing checkAlive"; }
        return {
            checkAlive: args['checkAlive']
        };
    },
    opennessTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.opennessTower)));
        return ecs.tower(args);
    },
    pushInsecurityButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.pushInsecurityButton)));
        return ecs.goalButton(args);
    },
    emotionResourceMap: function(args){
        return {
            emotionResourceMapComponent: ecs.emotionResourceMapComponent(args)
        };
    },
    obsessHimTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessHimTowerConstruction)));
        return ecs.construction(args);
    },
    memory: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory)));
        args["touchable"] = true;
        args["path"] = [];
        args["interactionKeys"] = [PARAMETERS.self];
        args["randomTraitPosition"] = false;
        args["health"] = (args["health"] === undefined) ? 225 : args["health"];
        args["panelKey"] = (args["panelKey"] === undefined) ? PARAMETERS.traitPanel : args["panelKey"];
        return {
            uiActionComponent: ecs.buildingUiActionComponent(args),
            memoryComponent: ecs.memoryComponent(args),
            experienceComponent: ecs.experienceComponent(args),
            createExecutables: [ecs.memoryFindPositionExec(args), ecs.builtSourceCreateExec(args)],
            timedDeathComponent: (PARAMETERS.timedMemories) ? ecs.timedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            entityManagerComponent: ecs.entityManagerComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            isaacEntityComponent: ecs.memoryIsaacEntityComponent(args),
            rendererComponents: [ecs.builtSourceRendererComponent(args)],
            focusTickResponseComponent: (args.aliveEntities) ? ecs.focusTickAliveMakerComponent(args) : undefined,
            tickComponent: ecs.memoryTickComponent(args),
            menuCloseComponent: ecs.traitMenuCloseComponent(args),
            personHeldComponent: (args.personHeld) ? ecs.personHeldComponent(args) : undefined,
            resourceComponent: undefined,
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killExtensions(args)],
            healthComponent: ecs.healthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            positionComponent: ecs.positionComponent(args),
            mapSpawnComponent: ecs.builtSourceMapSpawnComponent(args),
            junctionComponent: ecs.junctionComponent(args),
            playerMadeComponent: ecs.fixedPlayerMadeComponent(args)
        };
    },
    diveHurtButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.diveHurtButton)));
        return ecs.goalButton(args);
    },
    diveHurtGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.diveHurtGoal)));
        return ecs.worldGoal(args);
    },
    markTraitNew: function(args){
        return {
            execute: markTraitNewExec,
            particleEffect: "newTraitParticle"
        };
    },
    flirtYouGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtYouGoal)));
        return ecs.worldGoal(args);
    },
    guiltMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.guiltMed)));
        return ecs.creep(args);
    },
    towerHelpInfoPanel: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.towerHelpInfoPanel)));
        return ecs.helpInfoPanel(args);
    },
    damageUpgradeComponent: function(args){
        if (args.towerKeys === undefined){ throw "ECS fail " + args.key + " missing towerKeys"; }
        if (args.damageUpgrade === undefined){ throw "ECS fail " + args.key + " missing damageUpgrade"; }
        return {
            damageUpgrade: args['damageUpgrade'],
            towerKeys: args['towerKeys']
        };
    },
    pointNotification: function(args){
        args["notificationKey"] = PARAMETERS.addPoints;
        args["notificationArgs"] = {points: args.points};
        return {
            healthComponent: ecs.singleHealthComponent(args),
            notifyComponent: ecs.notifyComponent(args)
        };
    },
    supportNeedAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportNeedAction)));
        return ecs.currencyAction(args);
    },
    killTrainExec: function(args){
        if (args.source === undefined){ throw "ECS fail " + args.key + " missing source"; }
        return {
            source: args['source'],
            execute: killTrainExec
        };
    },
    relationship_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.relationship_ext)));
        return ecs.sourceExtension(args);
    },
    sourceExtension: function(args){
        args["touchable"] = true;
        return {
            rendererComponents: [ecs.sourceExtensionRenderComponent(args)],
            personHeldComponent: (args.personHeld) ? ecs.personHeldComponent(args) : undefined,
            createExecutables: [ecs.makeExtraPathsExec(args)],
            sourceExtensionComponent: ecs.sourceExtensionComponent(args),
            clickComponent: ecs.sourceExtensionClickComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.fixedPlayerMadeComponent(args)
        };
    },
    exploreStrengthButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.exploreStrengthButton)));
        return ecs.goalButton(args);
    },
    makeComplimentSwarmMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeComplimentSwarmMenu)));
        return ecs.goalCompleteMenu(args);
    },
    busyWorkPlaced: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.busyWorkPlaced)));
        return ecs.placedTower(args);
    },
    completeWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.completeWork)));
        return ecs.currency(args);
    },
    winGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.winGoal)));
        return ecs.worldGoal(args);
    },
    hundredHealthComponent: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hundredHealthComponent)));
        return {
            kill: killHealthComponent,
            damageFactor: (args["damageFactor"] === undefined) ? 1 : args["damageFactor"],
            health: args['health'],
            maxHealth: args['health']
        };
    },
    topic: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.topic)));
        return ecs.currency(args);
    },
    focusPanel: function(args){
        return {
            panelComponent: ecs.setPanelComponent(args),
            absolutePositionComponent: ecs.focusPanelAbsolutePositionComponent(args),
            rendererComponents: [ecs.focusPanelRenderComponent(args)],
            uiClickComponent: ecs.panelUiClickComponent(args)
        };
    },
    flashback_viceMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_viceMed)));
        return ecs.emotionResource(args);
    },
    worldGoalFocusPathStopComponent: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worldGoalFocusPathStopComponent)));
        return {
            currencyEntities: (args["currencyEntities"] === undefined) ? undefined : args["currencyEntities"],
            interactWithTrain: currencyRequestedInteractWithTrain,
            currencyEffect: (args["currencyEffect"] === undefined) ? undefined : args["currencyEffect"],
            currenciesNeededAtPoint: currencyRequestedCurrenciesNeededAtPoint,
            updateCurrencyDictWithStop: updateCurrencyDictWithStop,
            getCurrencyComponent: worldGoalGetCurrencyComponent,
            currenciesExistAtPoint: currenciesExistAtPoint,
            currenciesMadeAtPoint: (args["currenciesMadeAtPoint"] === undefined) ? emptyArrayFunction : args["currenciesMadeAtPoint"],
            isPathEnd: true,
            requiredOpinions: (args["requiredOpinions"] === undefined) ? [] : args["requiredOpinions"],
            percentComplete: currencyRequestedFocusPathStopPercentComplete,
            checkFocusStopDisabled: checkFocusStopDisabled,
            isDisabled: false,
            enableChecks: (args["enableChecks"] === undefined) ? [] : args["enableChecks"]
        };
    },
    startRelationHimGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startRelationHimGoal)));
        return ecs.worldGoal(args);
    },
    overcomeHurtButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.overcomeHurtButton)));
        return ecs.goalButton(args);
    },
    swallowOpinionKill: function(args){
        return {
            execute: swallowOpinionKill
        };
    },
    hurtingPathRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hurtingPathRelationship)));
        return ecs.pathMaker(args);
    },
    explainLearnHimFail: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.explainLearnHimFail)));
        return ecs.menuModifier(args);
    },
    clearTraitExec: function(args){
        if (args.trait === undefined){ throw "ECS fail " + args.key + " missing trait"; }
        return {
            trait: args['trait'],
            execute: clearTraitExec
        };
    },
    constructionComponent: function(args){
        if (args.currencyRequested === undefined){ throw "ECS fail " + args.key + " missing currencyRequested"; }
        if (args.constructionIdentifier === undefined){ throw "ECS fail " + args.key + " missing constructionIdentifier"; }
        return {
            constructionIdentifier: args['constructionIdentifier'],
            killWithoutPath: (args["killWithoutPath"] === undefined) ? false : args["killWithoutPath"],
            ticked: (args["ticked"] === undefined) ? false : args["ticked"],
            construct: construct,
            currencyRequested: args['currencyRequested'],
            origCurrencyRequested: _.clone(args.currencyRequested)
        };
    },
    helpPanelComponent: function(args){
        return {
            openHelpPanel: openHelpPanel
        };
    },
    allGoalPanelRenderComponent: function(args){
        return {
            insetColor: "#000000",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "uiBack",
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            priority: 18,
            render: outPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            specificRender: allGoalPanelRender,
            drawHelpButton: drawHelpButton
        };
    },
    obsessionDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessionDeposit)));
        return ecs.deposit(args);
    },
    casualSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.casualSmall)));
        return ecs.creep(args);
    },
    makeGainControlMenuExec: function(args){
        if (args.emotion === undefined){ throw "ECS fail " + args.key + " missing emotion"; }
        return {
            emotion: args['emotion'],
            execute: makeGainControlMenuExec,
            gainControlMenuKey: "gainControl"
        };
    },
    towerFocusTickResponseComponent: function(args){
        return {
            isReady: false,
            isWaiting: false,
            focusTick: towerFocusTick
        };
    },
    selfishPathHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfishPathHim)));
        return ecs.pathMaker(args);
    },
    learnHistoryMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.learnHistoryMenu)));
        return ecs.goalCompleteMenu(args);
    },
    selfishnessMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfishnessMineConstruction)));
        return ecs.construction(args);
    },
    checkQualityTickComponent: function(args){
        if (args.qualityKey === undefined){ throw "ECS fail " + args.key + " missing qualityKey"; }
        if (args.minQuality === undefined){ throw "ECS fail " + args.key + " missing minQuality"; }
        if (args.minQualityEntities === undefined){ throw "ECS fail " + args.key + " missing minQualityEntities"; }
        return {
            qualityKey: args['qualityKey'],
            tick: checkQualityTick,
            minQualityEntities: args['minQualityEntities'],
            minQuality: args['minQuality']
        };
    },
    makeDreamDeathMajorGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeDreamDeathMajorGoalConstruction)));
        return ecs.construction(args);
    },
    switch: function(args){
        return {
            replaceMarker: ecs.switchReplaceMarker(args)
        };
    },
    killDayEndComponent: function(args){
        args["dayEnd"] = dayEndKillEntity;
        return {
            dayEnd: (args["dayEnd"] === undefined) ? undefined : args["dayEnd"],
            dayStart: (args["dayStart"] === undefined) ? undefined : args["dayStart"],
            dayChange: (args["dayChange"] === undefined) ? undefined : args["dayChange"]
        };
    },
    helpGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpGoal)));
        return ecs.worldGoal(args);
    },
    rejectMeanlessGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.rejectMeanlessGoal)));
        return ecs.worldGoal(args);
    },
    busyWorkAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.busyWorkAction)));
        return ecs.currencyAction(args);
    },
    majorTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.majorTower)));
        return ecs.tower(args);
    },
    spellComponent: function(args){
        if (args.spellCost === undefined){ throw "ECS fail " + args.key + " missing spellCost"; }
        if (args.spellFn === undefined){ throw "ECS fail " + args.key + " missing spellFn"; }
        return {
            spellCost: args['spellCost'],
            spellButtonFunction: undefined,
            spellFn: args['spellFn']
        };
    },
    constructionMenuCloseComponent: function(args){
        return {
            execute: constructionMenuCloseExec
        };
    },
    damageUpgrade: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            damageUpgradeComponent: ecs.damageUpgradeComponent(args)
        };
    },
    creepRenderComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            priority: 12,
            image: args['image'],
            renderState: "default",
            render: currencyRender,
            renderPos: undefined
        };
    },
    makeOldFailSwarmMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeOldFailSwarmMenu)));
        return ecs.goalCompleteMenu(args);
    },
    impulseFocusPathStopComponent: function(args){
        return {
            interactWithTrain: impulseFocusStopInteractWithTrain,
            currenciesNeededAtPoint: (args["currenciesNeededAtPoint"] === undefined) ? emptyArrayFunction : args["currenciesNeededAtPoint"],
            currenciesMadeAtPoint: impulseFocusStopCurrenciesMadeAtPoint,
            isDisabled: false,
            currenciesExistAtPoint: currenciesExistAtPoint,
            updateCurrencyDictWithStop: updateCurrencyDictWithStop,
            isPathEnd: (args["isPathEnd"] === undefined) ? false : args["isPathEnd"],
            impulseCurrency: "impulse",
            checkFocusStopDisabled: checkFocusStopDisabled,
            requiredOpinions: (args["requiredOpinions"] === undefined) ? [] : args["requiredOpinions"],
            enableChecks: (args["enableChecks"] === undefined) ? [] : args["enableChecks"]
        };
    },
    shareJoyButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.shareJoyButton)));
        return ecs.towerButton(args);
    },
    interesting: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.interesting)));
        return ecs.currency(args);
    },
    notificationComponent: function(args){
        if (args.notificationFunctions === undefined){ throw "ECS fail " + args.key + " missing notificationFunctions"; }
        return {
            notificationFunctions: args['notificationFunctions'],
            serializeComponent: ecs.notificationSerializeComponent(args)
        };
    },
    sourceFocusPathStopComponent: function(args){
        return {
            interactWithTrain: falseFunction,
            currenciesNeededAtPoint: sourceCurrenciesNeededAtPoint,
            currenciesMadeAtPoint: (args["currenciesMadeAtPoint"] === undefined) ? emptyArrayFunction : args["currenciesMadeAtPoint"],
            isDisabled: false,
            currenciesExistAtPoint: currenciesExistAtPoint,
            updateCurrencyDictWithStop: updateCurrencyDictWithStop,
            isPathEnd: (args["isPathEnd"] === undefined) ? false : args["isPathEnd"],
            checkFocusStopDisabled: checkFocusStopDisabled,
            requiredOpinions: (args["requiredOpinions"] === undefined) ? [] : args["requiredOpinions"],
            enableChecks: (args["enableChecks"] === undefined) ? [] : args["enableChecks"]
        };
    },
    guiltEmoFlat: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.guiltEmoFlat)));
        return ecs.instantEmotionResource(args);
    },
    tryForConnectionYouButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryForConnectionYouButton)));
        return ecs.goalButton(args);
    },
    cursorRenderComponent: function(args){
        return {
            priority: 19,
            renderState: "default",
            render: cursorRender
        };
    },
    sourceRenderComponent: function(args){
        return {
            priority: 5,
            image: args['image'],
            renderState: "default",
            render: imageRender
        };
    },
    sadAttackMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sadAttackMine)));
        return ecs.emotionResource(args);
    },
    gameStateEntity: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.gameStateEntity)));
        return {
            rendererSystemComponent: ecs.rendererSystemComponent(args),
            uniqueComponent: ecs.assertUniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    traitMaker: function(args){
        return {
            traitMakerComponent: ecs.traitMakerComponent(args)
        };
    },
    buildPanelAbsolutePositionComponent: function(args){
        return {
            y: 678,
            x: 850,
            size: [174, 90]
        };
    },
    spendTimeWarmMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeWarmMenu)));
        return ecs.goalCompleteMenu(args);
    },
    instantEmotionResourceTickComponent: function(args){
        return {
            tick: instantEmotionResourceTick
        };
    },
    demolishPathRenderComponent: function(args){
        return {
            priority: 3,
            demolishPathButtonFunction: undefined,
            renderState: "default",
            render: demolishPathButtonRender
        };
    },
    obsession: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsession)));
        return ecs.currency(args);
    },
    talkInterestingButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkInterestingButton)));
        return ecs.goalButton(args);
    },
    reinforceCriticismMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reinforceCriticismMenu)));
        return ecs.goalCompleteMenu(args);
    },
    notifyComponent: function(args){
        if (args.notificationKey === undefined){ throw "ECS fail " + args.key + " missing notificationKey"; }
        if (args.notificationArgs === undefined){ throw "ECS fail " + args.key + " missing notificationArgs"; }
        return {
            notifyEntityKey: (args["notifyEntityKey"] === undefined) ? undefined : args["notifyEntityKey"],
            notificationKey: args['notificationKey'],
            notificationArgs: args['notificationArgs']
        };
    },
    connectFriendsButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.connectFriendsButton)));
        return ecs.goalButton(args);
    },
    opennessTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.opennessTowerConstruction)));
        return ecs.construction(args);
    },
    crueltyToInsecurity: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.crueltyToInsecurity)));
        return ecs.transformExec(args);
    },
    trySomethingMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.trySomethingMenu)));
        return ecs.goalCompleteMenu(args);
    },
    insecureMinePlaced: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecureMinePlaced)));
        return ecs.placedTower(args);
    },
    gameStageStartMenu: function(args){
        args["y"] = 5;
        args["x"] = width / 2 - 325;
        args["size"] = [650, 600];
        return {
            rendererComponents: [ecs.goalCompleteMenuRender(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            createExecutables: [ecs.goalCompleteMenuCreateExec(args)],
            goalCompleteMenuComponent: ecs.goalCompleteMenuComponent(args),
            panelComponent: ecs.goalCompleteMenuPanelComponent(args),
            pauseComponent: ecs.pauseComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            rebuildMenuComponent: ecs.rebuildMenuComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    takeOutFrustrationButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeOutFrustrationButton)));
        return ecs.goalButton(args);
    },
    oddityDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oddityDeposit)));
        return ecs.deposit(args);
    },
    toughTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.toughTowerConstruction)));
        return ecs.construction(args);
    },
    supportNeedTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportNeedTowerConstruction)));
        return ecs.construction(args);
    },
    hisEmotionDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisEmotionDeposit)));
        return ecs.deposit(args);
    },
    socialMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialMineConstruction)));
        return ecs.construction(args);
    },
    boostRenderComponent: function(args){
        return {
            priority: 6,
            renderState: args['planeOfExistence'],
            render: boostRender
        };
    },
    defineRoleGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.defineRoleGoal)));
        return ecs.worldGoal(args);
    },
    resourceFocusPathStopComponent: function(args){
        return {
            interactWithTrain: resourceInteractWithTrain,
            currenciesNeededAtPoint: (args["currenciesNeededAtPoint"] === undefined) ? emptyArrayFunction : args["currenciesNeededAtPoint"],
            currenciesMadeAtPoint: resourceCurrenciesMadeAtPoint,
            isDisabled: false,
            currenciesExistAtPoint: currenciesExistAtPoint,
            updateCurrencyDictWithStop: updateCurrencyDictWithStop,
            isPathEnd: (args["isPathEnd"] === undefined) ? false : args["isPathEnd"],
            checkFocusStopDisabled: checkFocusStopDisabled,
            requiredOpinions: (args["requiredOpinions"] === undefined) ? [] : args["requiredOpinions"],
            enableChecks: (args["enableChecks"] === undefined) ? [] : args["enableChecks"]
        };
    },
    memory_criticismSwarmYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_criticismSwarmYou)));
        return ecs.memory(args);
    },
    currencyActionComponent: function(args){
        if (args.towerKey === undefined){ throw "ECS fail " + args.key + " missing towerKey"; }
        return {
            nextIds: [],
            towerKey: args['towerKey'],
            entitiesOnConvert: (args["entitiesOnConvert"] === undefined) ? [] : args["entitiesOnConvert"],
            currenciesRequired: (args["currenciesRequired"] === undefined) ? [] : args["currenciesRequired"],
            towerIds: [],
            currenciesToMake: (args["currenciesToMake"] === undefined) ? [] : args["currenciesToMake"]
        };
    },
    relationshipMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.relationshipMineButton)));
        return ecs.resourceButton(args);
    },
    damageableComponent: function(args){
        if (args.emotion === undefined){ throw "ECS fail " + args.key + " missing emotion"; }
        if (args.emotionTags === undefined){ throw "ECS fail " + args.key + " missing emotionTags"; }
        return {
            emotion: args['emotion'],
            traits: (args["traits"] === undefined) ? [] : args["traits"],
            getAll: getAllEmotionParts,
            emotionTags: args['emotionTags'],
            damageEffects: []
        };
    },
    triggerCrisisGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.triggerCrisisGoalConstruction)));
        return ecs.construction(args);
    },
    entityPanelComponent: function(args){
        if (args.sourceId === undefined){ throw "ECS fail " + args.key + " missing sourceId"; }
        return {
            panelButtons: [],
            sourceId: args['sourceId'],
            expandPanel: expandPanel,
            minimized: true,
            canClose: true,
            closed: true,
            ignoreWhenMinimized: true
        };
    },
    memory_guiltFlatYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_guiltFlatYou)));
        return ecs.memory(args);
    },
    dreamDeath: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.dreamDeath)));
        return ecs.currency(args);
    },
    dailyEntityMakerComponent: function(args){
        if (args.dayStartEntity === undefined){ throw "ECS fail " + args.key + " missing dayStartEntity"; }
        if (args.dayCount === undefined){ throw "ECS fail " + args.key + " missing dayCount"; }
        return {
            dayCount: args['dayCount'],
            dayStartEntity: args['dayStartEntity'],
            daysToMake: args['dayCount']
        };
    },
    loosenUpMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.loosenUpMenu)));
        return ecs.goalCompleteMenu(args);
    },
    memory_resentYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_resentYou)));
        return ecs.memory(args);
    },
    openMenuMarkerRenderComponent: function(args){
        return {
            priority: 14,
            renderState: "default",
            render: openMenuMarkerRender
        };
    },
    socialWarmMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialWarmMineButton)));
        return ecs.resourceButton(args);
    },
    swarmTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.swarmTower)));
        return ecs.tower(args);
    },
    defineRoleGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.defineRoleGoalConstruction)));
        return ecs.construction(args);
    },
    mapSpawnComponent: function(args){
        if (args.mapSpawnKey === undefined){ throw "ECS fail " + args.key + " missing mapSpawnKey"; }
        return {
            mapSpawnPos: mapSpawnPos,
            mapPostSpawn: trueFunction,
            mapShouldSpawn: trueFunction,
            mapSpawn: mapSpawn,
            mapSpawnKey: args['mapSpawnKey']
        };
    },
    thankMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.thankMenu)));
        return ecs.goalCompleteMenu(args);
    },
    youRelationButtonBranch: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.youRelationButtonBranch)));
        return ecs.flagBranch(args);
    },
    pathButtonRenderComponent: function(args){
        return {
            priority: 1,
            renderState: "default",
            render: pathButtonRender,
            pathButtonFunction: undefined
        };
    },
    switchHelpGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.switchHelpGoal)));
        return ecs.switch(args);
    },
    swarmButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.swarmButton)));
        return ecs.towerButton(args);
    },
    disableHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.disableHim)));
        return ecs.disableTrait(args);
    },
    healEntities: function(args){
        return {
            execute: healEntities,
            entitiesToHeal: (args["entitiesToHeal"] === undefined) ? {} : args["entitiesToHeal"]
        };
    },
    rechargeTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.rechargeTowerConstruction)));
        return ecs.memoryConstruction(args);
    },
    gainControl_sadness: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.gainControl_sadness)));
        return ecs.gainControlMenu(args);
    },
    revertMemoryExec: function(args){
        if (args.sourceId === undefined){ throw "ECS fail " + args.key + " missing sourceId"; }
        return {
            sourceId: args['sourceId'],
            execute: revertMemoryExec
        };
    },
    nameRenderComponent: function(args){
        return {
            priority: 8,
            renderState: "default",
            name: args['name'],
            render: nameRender
        };
    },
    warmPathYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.warmPathYou)));
        return ecs.pathMaker(args);
    },
    aloneFlatYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.aloneFlatYou)));
        return ecs.emotionSource(args);
    },
    anger: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.anger)));
        return ecs.creep(args);
    },
    himSupportAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.himSupportAction)));
        return ecs.currencyAction(args);
    },
    interestingDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.interestingDeposit)));
        return ecs.deposit(args);
    },
    complimentFlat: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentFlat)));
        return ecs.instantEmotionResource(args);
    },
    socialMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialMineButton)));
        return ecs.resourceButton(args);
    },
    demolishButton: function(args){
        return {
            rendererComponents: [ecs.demolishButtonRenderComponent(args)]
        };
    },
    selfDistractionAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfDistractionAction)));
        return ecs.currencyAction(args);
    },
    makeDreamDeathMajorButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeDreamDeathMajorButton)));
        return ecs.goalButton(args);
    },
    killResourceCurrencies: function(args){
        return {
            execute: killResourceCurrencies
        };
    },
    triggerCrisisGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.triggerCrisisGoal)));
        return ecs.worldGoal(args);
    },
    currencyPathComponent: function(args){
        return {
            currencies: (args["currencies"] === undefined) ? [] : args["currencies"],
            buildingActions: (args["buildingActions"] === undefined) ? [] : args["buildingActions"]
        };
    },
    takeConnectDone: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeConnectDone)));
        return ecs.endGoal(args);
    },
    worthlessFeelMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worthlessFeelMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    pain: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.pain)));
        return ecs.currency(args);
    },
    choreMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.choreMenu)));
        return ecs.goalCompleteMenu(args);
    },
    accuseSelfishButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.accuseSelfishButton)));
        return ecs.goalButton(args);
    },
    flirtYouButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtYouButton)));
        return ecs.goalButton(args);
    },
    noSupportGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.noSupportGoal)));
        return ecs.worldGoal(args);
    },
    mistrustJoyTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.mistrustJoyTowerConstruction)));
        return ecs.construction(args);
    },
    startPaths: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startPaths)));
        return ecs.entityReplace(args);
    },
    searchWorthGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.searchWorthGoal)));
        return ecs.worldGoal(args);
    },
    placedTower: function(args){
        return {
            replaceMarker: ecs.placedTowerReplaceMarker(args)
        };
    },
    reinforceOldFailMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reinforceOldFailMenu)));
        return ecs.goalCompleteMenu(args);
    },
    worldGoalTimedDeathComponent: function(args){
        return {
            killOnTimeOut: (args["killOnTimeOut"] === undefined) ? [] : args["killOnTimeOut"],
            timeToDeath: args['timeToDeath'],
            deathExecs: [ecs.trackActionables(args)],
            makeOnTimeOut: (args["makeOnTimeOut"] === undefined) ? [] : args["makeOnTimeOut"]
        };
    },
    socialCleverMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialCleverMineConstruction)));
        return ecs.construction(args);
    },
    memoryResourceFocusTickResponseComponent: function(args){
        return {
            firstTick: true,
            destination: (args["destination"] === undefined) ? undefined : args["destination"],
            focusTick: resourceFocusTick,
            focusTickHook: triggerFlashback,
            flashbackChance: 0.25,
            emotionTags: (args["emotionTags"] === undefined) ? undefined : args["emotionTags"]
        };
    },
    memoryExtension: function(args){
        args["touchable"] = true;
        args["image"] = args.source ? args.source.rendererComponents[0].image : null;
        args["name"] = args.source ? args.source.identityComponent.name : null;
        args["key"] = args.source ? (args.source.identityComponent.key + '_ext') : null;
        args["sourceKey"] = args.source ? args.source.identityComponent.key : null;
        return {
            rendererComponents: [ecs.sourceExtensionRenderComponent(args)],
            positionComponent: ecs.positionComponent(args),
            personHeldComponent: (args.personHeld) ? ecs.personHeldComponent(args) : undefined,
            createExecutables: [ecs.makeExtraPathsExec(args)],
            clickComponent: ecs.sourceExtensionClickComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            sourceExtensionComponent: ecs.sourceExtensionComponent(args),
            playerMadeComponent: ecs.fixedPlayerMadeComponent(args)
        };
    },
    reachOutGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reachOutGoalConstruction)));
        return ecs.construction(args);
    },
    trainVelocityComponent: function(args){
        if (args.trainPath === undefined){ throw "ECS fail " + args.key + " missing trainPath"; }
        if (args.allPaths === undefined){ throw "ECS fail " + args.key + " missing allPaths"; }
        return {
            lastStop: undefined,
            trainStops: undefined,
            stopIndex: 0,
            currentPath: undefined,
            ticks: 0,
            isMoving: false,
            allPaths: args['allPaths'],
            trainPath: args['trainPath'],
            velocity: 1
        };
    },
    makeCriticismFlatGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeCriticismFlatGoalConstruction)));
        return ecs.construction(args);
    },
    reachOutDone: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reachOutDone)));
        return ecs.endGoal(args);
    },
    printKillExec: function(args){
        return {
            execute: printKillExec
        };
    },
    steamAchievementComponent: function(args){
        if (args.keyToCheck === undefined){ throw "ECS fail " + args.key + " missing keyToCheck"; }
        if (args.steamAchievementKey === undefined){ throw "ECS fail " + args.key + " missing steamAchievementKey"; }
        return {
            steamAchievementKey: args['steamAchievementKey'],
            keyToCheck: args['keyToCheck']
        };
    },
    gainControlMenuRender: function(args){
        if (args.emotion === undefined){ throw "ECS fail " + args.key + " missing emotion"; }
        if (args.textColor === undefined){ throw "ECS fail " + args.key + " missing textColor"; }
        if (args.text === undefined){ throw "ECS fail " + args.key + " missing text"; }
        if (args.barColor === undefined){ throw "ECS fail " + args.key + " missing barColor"; }
        return {
            emotion: args['emotion'],
            priority: 24,
            fullAnimationTime: 0.25,
            render: gainControlMenuRender,
            brainImage: "miniSelf",
            barWidth: 50,
            percentageComplete: 0,
            barColor: args['barColor'],
            text: args['text'],
            barPos: [250, 150],
            backImage: "uiBack",
            renderTime: 0,
            brainPos: [265, 152],
            textColor: args['textColor'],
            renderState: "default",
            resetVelTime: 0,
            brainVel: 0
        };
    },
    traitMakerComponent: function(args){
        if (args.traitMakerEmotion === undefined){ throw "ECS fail " + args.key + " missing traitMakerEmotion"; }
        if (args.traitsToMake === undefined){ throw "ECS fail " + args.key + " missing traitsToMake"; }
        return {
            traitMakerEmotion: args['traitMakerEmotion'],
            traitsToMake: args['traitsToMake']
        };
    },
    oldFailSwarm: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldFailSwarm)));
        return ecs.instantEmotionResource(args);
    },
    resource: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        return {
            interactionComponent: ecs.interactionComponent(args),
            junctionComponent: ecs.junctionComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args)],
            focusTickResponseComponent: ecs.resourceFocusTickResponseComponent(args),
            managedComponent: ecs.managedComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)],
            focusPathStopComponent: ecs.resourceFocusPathStopComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killResourceCurrencies(args)],
            descriptionComponent: ecs.descriptionComponent(args),
            resourceComponent: ecs.resourceComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    crueltyTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.crueltyTower)));
        return ecs.tower(args);
    },
    faithCrisis_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.faithCrisis_ext)));
        return ecs.sourceExtension(args);
    },
    reinforceViceMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reinforceViceMenu)));
        return ecs.goalCompleteMenu(args);
    },
    workHappy: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.workHappy)));
        return ecs.instantEmotionResource(args);
    },
    stupid: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.stupid)));
        return ecs.currency(args);
    },
    generousButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.generousButton)));
        return ecs.towerButton(args);
    },
    convinceActivityGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.convinceActivityGoal)));
        return ecs.worldGoal(args);
    },
    worldGoalRenderComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            outlineImage: false,
            render: worldGoalRender,
            wobble: 0,
            image: args['image'],
            priority: 6,
            timeToBlink: 1,
            newImage: "newOutline",
            getWobble: getWobble,
            renderState: "default",
            renderTrainIcon: renderTrainIcon,
            outlineTime: 0
        };
    },
    getOverBadWorkGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getOverBadWorkGoalConstruction)));
        return ecs.construction(args);
    },
    currencyOverloadComponent: function(args){
        if (args.resourceKey === undefined){ throw "ECS fail " + args.key + " missing resourceKey"; }
        if (args.currencyKey === undefined){ throw "ECS fail " + args.key + " missing currencyKey"; }
        if (args.overloadEntities === undefined){ throw "ECS fail " + args.key + " missing overloadEntities"; }
        if (args.currencyCount === undefined){ throw "ECS fail " + args.key + " missing currencyCount"; }
        return {
            resourceKey: args['resourceKey'],
            currencyCount: args['currencyCount'],
            currencyKey: args['currencyKey'],
            overloadEntities: args['overloadEntities']
        };
    },
    needHelpGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needHelpGoalConstruction)));
        return ecs.construction(args);
    },
    viceTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.viceTower)));
        return ecs.tower(args);
    },
    selfDistractionButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfDistractionButton)));
        return ecs.towerButton(args);
    },
    pushTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.pushTower)));
        return ecs.tower(args);
    },
    sadAttackMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sadAttackMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    supportCrisisMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportCrisisMenu)));
        return ecs.goalCompleteMenu(args);
    },
    talkAboutYouMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkAboutYouMenu)));
        return ecs.goalCompleteMenu(args);
    },
    obsessionsAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessionsAction)));
        return ecs.currencyAction(args);
    },
    swarmTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.swarmTowerConstruction)));
        return ecs.construction(args);
    },
    talkAboutHimMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkAboutHimMenu)));
        return ecs.goalCompleteMenu(args);
    },
    probedProblem: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.probedProblem)));
        return ecs.currency(args);
    },
    splitReplace: function(args){
        return {
            replaceMarker: ecs.splitReplaceMarker(args)
        };
    },
    probeTopicMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.probeTopicMenu)));
        return ecs.goalCompleteMenu(args);
    },
    flirtAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtAction)));
        return ecs.currencyAction(args);
    },
    flashback_sadnessConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_sadnessConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    controlPanelKeyPressComponent: function(args){
        return {
            handleKeyPress: controlPanelHandleKeyPress
        };
    },
    instantEmotionResource: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        args["playerKillable"] = false;
        return {
            focusPathStopComponent: ecs.resourceFocusPathStopComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args)],
            focusTickResponseComponent: ecs.resourceFocusTickResponseComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            managedComponent: ecs.managedComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)].concat([ecs.emotionResourceDifficultyExec(args)]),
            junctionComponent: ecs.junctionComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killResourceCurrencies(args)],
            resourceComponent: ecs.resourceComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            loseControlExec: ecs.killEntity(args),
            playerMadeComponent: ecs.playerMadeComponent(args),
            tickComponent: ecs.instantEmotionResourceTickComponent(args)
        };
    },
    feedCrisisGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.feedCrisisGoalConstruction)));
        return ecs.construction(args);
    },
    caring: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.caring)));
        return ecs.currency(args);
    },
    opennessAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.opennessAction)));
        return ecs.currencyAction(args);
    },
    capable: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.capable)));
        return ecs.trait(args);
    },
    rendererComponent: function(args){
        if (args.render === undefined){ throw "ECS fail " + args.key + " missing render"; }
        if (args.priority === undefined){ throw "ECS fail " + args.key + " missing priority"; }
        return {
            priority: args['priority'],
            renderState: "default",
            render: args['render']
        };
    },
    makeCriticismFlatButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeCriticismFlatButton)));
        return ecs.goalButton(args);
    },
    disciplinePathHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.disciplinePathHim)));
        return ecs.pathMaker(args);
    },
    askForBeliefGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askForBeliefGoal)));
        return ecs.worldGoal(args);
    },
    towerTickComponent: function(args){
        return {
            tick: towerTick,
            timeToAttrition: (args["timeToAttrition"] === undefined) ? PARAMETERS.dayTicks : args["timeToAttrition"]
        };
    },
    insecureSwarmYouMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecureSwarmYouMine)));
        return ecs.emotionResource(args);
    },
    requestComponent: function(args){
        if (args.currencyRequested === undefined){ throw "ECS fail " + args.key + " missing currencyRequested"; }
        return {
            currencyRequested: args['currencyRequested']
        };
    },
    sourceExtensionComponent: function(args){
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        return {
            sourceKey: args['sourceKey']
        };
    },
    creepDeathRenderComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            timeLeft: 1,
            render: creepDeathRender,
            renderPos: (args["renderPos"] === undefined) ? undefined : args["renderPos"],
            image: args['image'],
            priority: 12,
            renderState: "default",
            size: [20, 17]
        };
    },
    askHelpButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askHelpButton)));
        return ecs.goalButton(args);
    },
    switchFascinateButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.switchFascinateButton)));
        return ecs.switch(args);
    },
    insecureSwarmHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecureSwarmHim)));
        return ecs.instantEmotionResource(args);
    },
    pushButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.pushButton)));
        return ecs.towerButton(args);
    },
    worthlessHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worthlessHim)));
        return ecs.instantEmotionResource(args);
    },
    checkQuality: function(args){
        return {
            tickComponent: ecs.checkQualityTickComponent(args)
        };
    },
    feelUselessGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.feelUselessGoal)));
        return ecs.worldGoal(args);
    },
    builtSourceCreateExec: function(args){
        return {
            sector: (args["sector"] === undefined) ? undefined : args["sector"],
            skipBuiltSourceCreate: (args["skipBuiltSourceCreate"] === undefined) ? false : args["skipBuiltSourceCreate"],
            execute: builtSourceCreateExec,
            startManagedEntities: (args["startManagedEntities"] === undefined) ? [] : args["startManagedEntities"],
            randomTraitPosition: (args["randomTraitPosition"] === undefined) ? true : args["randomTraitPosition"]
        };
    },
    shameBurstMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.shameBurstMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    insecureMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecureMine)));
        args["touchable"] = true;
        args["canExpandInto"] = false;
        args["playerKillable"] = false;
        return {
            focusPathStopComponent: ecs.resourceFocusPathStopComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args)],
            focusTickResponseComponent: ecs.resourceFocusTickResponseComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            managedComponent: ecs.managedComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)],
            resourceComponent: ecs.resourceComponent(args),
            junctionComponent: ecs.junctionComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killResourceCurrencies(args)],
            tickComponent: ecs.instantEmotionResourceTickComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    meditativeMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.meditativeMine)));
        return ecs.resource(args);
    },
    defineRoleButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.defineRoleButton)));
        return ecs.goalButton(args);
    },
    beSupportedGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.beSupportedGoalConstruction)));
        return ecs.construction(args);
    },
    trainPathMakerKill: function(args){
        return {
            execute: trainPathMakerKill
        };
    },
    needWorkGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needWorkGoal)));
        return ecs.worldGoal(args);
    },
    paramPath: function(args){
        return {
            createExecutables: [ecs.paramPathExec(args), ecs.killEntity(args)]
        };
    },
    hisEmotion: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisEmotion)));
        return ecs.currency(args);
    },
    makeWorkWinMajorMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeWorkWinMajorMenu)));
        return ecs.goalCompleteMenu(args);
    },
    killIfFlagExec: function(args){
        return {
            killIfFlag: (args["killIfFlag"] === undefined) ? undefined : args["killIfFlag"],
            execute: killIfFlagExec
        };
    },
    stupidDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.stupidDeposit)));
        return ecs.deposit(args);
    },
    panelTrackComponent: function(args){
        return {
            closeTrackedPanel: closeTrackedPanel,
            panelsOpened: [],
            closeAllPanels: closeAllPanels,
            trackPanels: trackPanels
        };
    },
    trainPathSecondRender: function(args){
        return {
            priority: 3,
            image: "outline",
            renderState: "default",
            render: trainPathSecondRender
        };
    },
    mistrustJoyTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.mistrustJoyTower)));
        return ecs.tower(args);
    },
    takeStrengthGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeStrengthGoal)));
        return ecs.worldGoal(args);
    },
    exploreNewMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.exploreNewMenu)));
        return ecs.goalCompleteMenu(args);
    },
    findUsefulResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findUsefulResult)));
        return ecs.randomReplace(args);
    },
    crueltyAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.crueltyAction)));
        return ecs.currencyAction(args);
    },
    worldGoalParticleEffect: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            lifeSentinelComponent: ecs.worldGoalParticleEffectLifeSentinelComponent(args),
            rendererComponents: [ecs.particleEffectRenderComponent(args)]
        };
    },
    constructionFocusPathStopComponent: function(args){
        return {
            currencyEntities: (args["currencyEntities"] === undefined) ? undefined : args["currencyEntities"],
            interactWithTrain: currencyRequestedInteractWithTrain,
            currencyEffect: (args["currencyEffect"] === undefined) ? undefined : args["currencyEffect"],
            currenciesNeededAtPoint: currencyRequestedCurrenciesNeededAtPoint,
            updateCurrencyDictWithStop: updateCurrencyDictWithStop,
            getCurrencyComponent: constructionGetCurrencyComponent,
            currenciesExistAtPoint: currenciesExistAtPoint,
            currenciesMadeAtPoint: (args["currenciesMadeAtPoint"] === undefined) ? emptyArrayFunction : args["currenciesMadeAtPoint"],
            isPathEnd: true,
            requiredOpinions: (args["requiredOpinions"] === undefined) ? [] : args["requiredOpinions"],
            percentComplete: currencyRequestedFocusPathStopPercentComplete,
            checkFocusStopDisabled: checkFocusStopDisabled,
            isDisabled: false,
            enableChecks: (args["enableChecks"] === undefined) ? [] : args["enableChecks"]
        };
    },
    mistrustJoyPlaced: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.mistrustJoyPlaced)));
        return ecs.placedTower(args);
    },
    hurtingPathClever: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hurtingPathClever)));
        return ecs.pathMaker(args);
    },
    partnerInfo: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.partnerInfo)));
        return ecs.currency(args);
    },
    depositTickComponent: function(args){
        return {
            tick: depositTick
        };
    },
    supportAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportAction)));
        return ecs.currencyAction(args);
    },
    criticizeSelfButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticizeSelfButton)));
        return ecs.goalButton(args);
    },
    flipHurt: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flipHurt)));
        return ecs.pairTransform(args);
    },
    setHimRelation: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.setHimRelation)));
        return ecs.setFlag(args);
    },
    pairTransform: function(args){
        return {
            replaceMarker: ecs.pairTransformMarker(args)
        };
    },
    goalCompleteMenuRender: function(args){
        return {
            flipModeFunction: undefined,
            fullAnimationTime: 7,
            yTextOffset: 5,
            closeFunction: undefined,
            image: (args["image"] === undefined) ? "activeHex" : args["image"],
            height: (args["height"] === undefined) ? undefined : args["height"],
            drawPanelButton: drawPanelButton,
            animatingTime: 0.2,
            descriptionTime: 0.5,
            renderState: "default",
            insetColor: "#000000",
            render: outPanelRender,
            titleTime: 0.4,
            priority: 19,
            sourceTrait: (args["sourceTrait"] === undefined) ? undefined : args["sourceTrait"],
            snapPanelPos: snapPanelPos,
            carousel: undefined,
            textColor: "#000000",
            backImage: "uiBack",
            drawImageButton: drawImageButton,
            expandRect: [args.x, args.y, args.size[0], args.size[1]],
            renderTime: 0,
            getFlipModeFunction: goalCompleteMenuFlipMode,
            completeText: (args["completeText"] === undefined) ? "" : args["completeText"],
            drawHelpButton: drawHelpButton,
            showingDescription: true,
            expandFunction: undefined,
            endGame: (args["endGame"] === undefined) ? false : args["endGame"],
            showPoints: (args["showPoints"] === undefined) ? false : args["showPoints"],
            specificRender: goalCompleteMenuRender
        };
    },
    gameStartMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.gameStartMenu)));
        return ecs.goalCompleteMenu(args);
    },
    choreReplaceMarker: function(args){
        return {
            traitKey: "restLife",
            getReplaceKeys: choreReplaceMarker,
            goalKeys: ["choreGoal"]
        };
    },
    sharePainGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sharePainGoal)));
        return ecs.worldGoal(args);
    },
    reinforceStupidMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reinforceStupidMenu)));
        return ecs.goalCompleteMenu(args);
    },
    beBelievedInGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.beBelievedInGoal)));
        return ecs.worldGoal(args);
    },
    relationshipPathGood: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.relationshipPathGood)));
        return ecs.pathMaker(args);
    },
    currencyNotificationComponent: function(args){
        if (args.notificationKey === undefined){ throw "ECS fail " + args.key + " missing notificationKey"; }
        return {
            notificationFunctions: simpleDict(args.notificationKey, addNotificationCurrency),
            serializeComponent: ecs.notificationSerializeComponent(args),
            notificationKey: args['notificationKey']
        };
    },
    particleEffectRenderComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        if (args.effectPos === undefined){ throw "ECS fail " + args.key + " missing effectPos"; }
        if (args.effectRadius === undefined){ throw "ECS fail " + args.key + " missing effectRadius"; }
        return {
            priority: 14,
            startParticles: (args["startParticles"] === undefined) ? 20 : args["startParticles"],
            render: particleEffectRender,
            impulseTimeToCheck: (args["impulseTimeToCheck"] === undefined) ? 0.05 : args["impulseTimeToCheck"],
            image: args['image'],
            effectPos: args['effectPos'],
            particles: [],
            effectRadius: args['effectRadius'],
            timeToCheck: 0.05,
            renderState: "default",
            makeParticle: makeParticle
        };
    },
    helpDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpDeposit)));
        return ecs.deposit(args);
    },
    buildPanelRenderComponent: function(args){
        return {
            drawImageButton: drawImageButton,
            textColor: "#000000",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "opaqueBack",
            insetColor: "#000000",
            animatingTime: 0.1,
            priority: 19,
            render: buildPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            demolishButtonFunction: undefined,
            renderTime: 0,
            demolishPathButtonFunction: undefined,
            settingsFunction: undefined,
            renderState: "default",
            drawHelpButton: drawHelpButton,
            specificRender: args['specificRender'],
            pathButtonFunction: undefined
        };
    },
    creepAcceptComponent: function(args){
        return {
            creepHitEntities: (args["creepHitEntities"] === undefined) ? PARAMETERS.creepHit : args["creepHitEntities"],
            creepAccept: creepAccept
        };
    },
    growHisWork: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.expandTrait(args)]
        };
    },
    personResource: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        return {
            focusPathStopComponent: ecs.resourceFocusPathStopComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args)],
            focusTickResponseComponent: ecs.resourceFocusTickResponseComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            managedComponent: ecs.managedComponent(args),
            personHeldComponent: ecs.personHeldComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)],
            junctionComponent: ecs.junctionComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killResourceCurrencies(args)],
            resourceComponent: ecs.resourceComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    tower: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        args["isPathEnd"] = (args["isPathEnd"] === undefined) ? (args.damageMultipliers ? true : false) : args["isPathEnd"];
        args["tags"] = (args["tags"] === undefined) ? [args.key] : args["tags"];
        return {
            junctionComponent: ecs.junctionComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args), ecs.damageRenderComponent(args)],
            focusTickResponseComponent: ecs.towerFocusTickResponseComponent(args),
            managedComponent: ecs.managedComponent(args),
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            damageComponent: (args.damageMultipliers) ? ecs.damageComponent(args) : undefined,
            healthModifyComponent: ecs.healthModifyComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)].concat([ecs.towerCreateExec(args)]),
            focusPathStopComponent: ecs.towerFocusPathStopComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            tickComponent: ecs.towerTickComponent(args),
            towerComponent: ecs.towerComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    notifyEntityMakerNotificationComponent: function(args){
        if (args.count === undefined){ throw "ECS fail " + args.key + " missing count"; }
        if (args.entitiesToMake === undefined){ throw "ECS fail " + args.key + " missing entitiesToMake"; }
        if (args.notificationArgs === undefined){ throw "ECS fail " + args.key + " missing notificationArgs"; }
        return {
            count: args['count'],
            notificationArgs: args['notificationArgs'],
            serializeComponent: ecs.notificationSerializeComponent(args),
            notificationFunctions: simpleDict(args.notificationChecked, notifyEntityMakerFn),
            impulseCount: args['count'],
            entitiesToMake: args['entitiesToMake']
        };
    },
    killTowerButtonExec: function(args){
        return {
            execute: killTowerButtonExec,
            killTowersOnDeath: (args["killTowersOnDeath"] === undefined) ? false : args["killTowersOnDeath"]
        };
    },
    traitMenuCloseComponent: function(args){
        return {
            execute: traitMenuCloseExec
        };
    },
    dayResponseComponent: function(args){
        return {
            dayEnd: (args["dayEnd"] === undefined) ? undefined : args["dayEnd"],
            dayStart: (args["dayStart"] === undefined) ? undefined : args["dayStart"],
            dayChange: (args["dayChange"] === undefined) ? undefined : args["dayChange"]
        };
    },
    reachOutBranch: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reachOutBranch)));
        return ecs.flagBranch(args);
    },
    needBusyButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needBusyButton)));
        return ecs.towerButton(args);
    },
    makeWorkWinMajorGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeWorkWinMajorGoalConstruction)));
        return ecs.construction(args);
    },
    critical: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.critical)));
        return ecs.trait(args);
    },
    gainControl_anger: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.gainControl_anger)));
        return ecs.gainControlMenu(args);
    },
    improveQualityExec: function(args){
        return {
            qualityDiff: (args["qualityDiff"] === undefined) ? 1 : args["qualityDiff"],
            execute: improveQuality,
            checkAgainstQuality: (args["checkAgainstQuality"] === undefined) ? true : args["checkAgainstQuality"],
            entitiesToMake: (args["entitiesToMake"] === undefined) ? undefined : args["entitiesToMake"],
            qualityEntity: (args["qualityEntity"] === undefined) ? undefined : args["qualityEntity"]
        };
    },
    notificationCurrency: function(args){
        return {
            notificationCurrencyComponent: ecs.notificationCurrencyComponent(args),
            notificationComponents: [ecs.currencyNotificationComponent(args)]
        };
    },
    killCapable: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.killCapable)));
        return ecs.entityKill(args);
    },
    majorButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.majorButton)));
        return ecs.towerButton(args);
    },
    executeComponent: function(args){
        if (args.executable === undefined){ throw "ECS fail " + args.key + " missing executable"; }
        return {
            executable: args['executable'],
            ticks: 0,
            requiresActive: (args["requiresActive"] === undefined) ? false : args["requiresActive"],
            impulseTicks: (args["impulseTicks"] === undefined) ? 10 : args["impulseTicks"]
        };
    },
    insecureSwarmYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecureSwarmYou)));
        return ecs.emotionSource(args);
    },
    goalCompleteMenuPanelComponent: function(args){
        return {
            panelButtons: [],
            expandPanel: expandPanel,
            minimized: false,
            canClose: true,
            closed: false,
            ignoreWhenMinimized: false
        };
    },
    findUsefulGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findUsefulGoal)));
        return ecs.worldGoal(args);
    },
    disableTraitComponent: function(args){
        if (args.traitsToDisable === undefined){ throw "ECS fail " + args.key + " missing traitsToDisable"; }
        return {
            checkTraitDisabled: checkTraitDisabled,
            traitsToDisable: args['traitsToDisable']
        };
    },
    oldFailMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldFailMineButton)));
        return ecs.resourceButton(args);
    },
    conditionalMake: function(args){
        return {
            replaceMarker: ecs.conditionalMakeReplaceMarker(args)
        };
    },
    searchingWorthToInsecurity: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.searchingWorthToInsecurity)));
        return ecs.transformExec(args);
    },
    hisValueDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisValueDeposit)));
        return ecs.deposit(args);
    },
    hisBadWorkToFaithCrisis: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisBadWorkToFaithCrisis)));
        return ecs.transformExec(args);
    },
    toughAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.toughAction)));
        return ecs.currencyAction(args);
    },
    strengthMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.strengthMineConstruction)));
        return ecs.construction(args);
    },
    worthlessToInsecurity: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worthlessToInsecurity)));
        return ecs.transformExec(args);
    },
    triggerCrisisMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.triggerCrisisMenu)));
        return ecs.goalCompleteMenu(args);
    },
    hisBadWorkToRestless: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisBadWorkToRestless)));
        return ecs.transformExec(args);
    },
    sharePainResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sharePainResult)));
        return ecs.randomReplace(args);
    },
    towerTickModifier: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.towerTickModifier)));
        return {
            healthComponent: ecs.singleHealthComponent(args),
            tickModifyComponent: ecs.tickModifyComponent(args),
            rendererComponents: [ecs.towerTickModifierRenderComponent(args)],
            dayResponseComponent: ecs.killDayEndComponent(args),
            timedDeathComponent: ecs.timedDeathComponent(args)
        };
    },
    shameBurst: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.shameBurst)));
        return ecs.emotionSource(args);
    },
    dreamDeathDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.dreamDeathDeposit)));
        return ecs.deposit(args);
    },
    startRelationYouGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startRelationYouGoalConstruction)));
        return ecs.construction(args);
    },
    stateTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.stateTower)));
        return ecs.tower(args);
    },
    toastRenderComponent: function(args){
        return {
            priority: 18,
            renderState: "default",
            render: toastRender
        };
    },
    flashback_joy: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_joy)));
        return ecs.emotionResource(args);
    },
    infiniteEmotionSourceComponent: function(args){
        return {
            spawnComplete: resetEmotionSource,
            border: "#ffff00",
            emotions: unrollDict(args.emotionsToAdd)
        };
    },
    fearTickModifyComponent: function(args){
        return {
            tickFactor: args['tickFactor'],
            distractFactor: args['distractFactor'],
            fearFrozen: 0,
            tickModifyInteraction: fearTickModifyInteraction,
            towerId: args['towerId']
        };
    },
    learnHimResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.learnHimResult)));
        return ecs.randomReplace(args);
    },
    learnHimGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.learnHimGoalConstruction)));
        return ecs.construction(args);
    },
    helpValueTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpValueTowerConstruction)));
        return ecs.construction(args);
    },
    guiltEmo: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.guiltEmo)));
        return ecs.splitReplace(args);
    },
    strengthDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.strengthDeposit)));
        return ecs.deposit(args);
    },
    memoryGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memoryGoal)));
        args["touchable"] = true;
        args["particleKey"] = PARAMETERS.newParticle;
        args["startEntityKey"] = args.sourceKey;
        args["canExpandInto"] = false;
        args["playerKillable"] = !!(args.constructed);
        args["killOnTransform"] = (args["killOnTransform"] === undefined) ? false : args["killOnTransform"];
        return {
            uiActionComponent: ecs.buildingUiActionComponent(args),
            onTraitComponent: ecs.onTraitComponent(args),
            goalTrackComponent: ecs.memoryGoalTrackComponent(args),
            createExecutables: [ecs.checkManagedComponentExec(args), (args.randomPosition) ? ecs.randomOpenPositionExec(args) : undefined, ecs.makeExtraPathsExec(args), ecs.chkForPlayerInterrupt(args), ecs.buildingConnectExec(args), (args.timeToDeath) ? ecs.timedDifficultyModifyExec(args) : undefined],
            timedDeathComponent: (args.timeToDeath) ? ecs.worldGoalTimedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            rendererComponents: [ecs.worldGoalRenderComponent(args), ecs.progressRenderComponent(args), ecs.timedDeathRenderComponent(args)],
            focusTickResponseComponent: (args.aliveEntities) ? ecs.aliveMakeComponent(args) : undefined,
            managedComponent: (args.sourceTrait) ? ecs.managedComponent(args) : undefined,
            flipComponent: (args.flipEntity) ? ecs.flipComponent(args) : undefined,
            worldGoalComponent: ecs.worldGoalComponent(args),
            focusPathStopComponent: ecs.worldGoalFocusPathStopComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            positionComponent: ecs.positionComponent(args),
            notificationComponents: [ecs.worldGoalNotificationComponent(args)],
            junctionComponent: ecs.junctionComponent(args),
            pauseComponent: ecs.pauseComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    sadness: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sadness)));
        return ecs.creep(args);
    },
    guiltFlatYouMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.guiltFlatYouMine)));
        return ecs.emotionResource(args);
    },
    makeSlowWorkFlatGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeSlowWorkFlatGoalConstruction)));
        return ecs.construction(args);
    },
    makeDreamDeathMajorMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeDreamDeathMajorMenu)));
        return ecs.goalCompleteMenu(args);
    },
    splitReplaceMarker: function(args){
        if (args.source === undefined){ throw "ECS fail " + args.key + " missing source"; }
        if (args.youKeys === undefined){ throw "ECS fail " + args.key + " missing youKeys"; }
        if (args.himKeys === undefined){ throw "ECS fail " + args.key + " missing himKeys"; }
        return {
            source: args['source'],
            himKeys: args['himKeys'],
            youKeys: args['youKeys'],
            getReplaceKeys: splitReplaceGetKeys
        };
    },
    getFeedbackGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getFeedbackGoalConstruction)));
        return ecs.construction(args);
    },
    askHelpMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askHelpMenu)));
        return ecs.goalCompleteMenu(args);
    },
    casualSwarmYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.casualSwarmYou)));
        return ecs.emotionSource(args);
    },
    completeWorkFull: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.completeWorkFull)));
        return ecs.entityReplace(args);
    },
    selfish: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfish)));
        return ecs.trait(args);
    },
    rechargeAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.rechargeAction)));
        return ecs.currencyAction(args);
    },
    youPathInsecurity: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.youPathInsecurity)));
        return ecs.pathMaker(args);
    },
    depositPositionExec: function(args){
        return {
            execute: depositPositionExec,
            randomPosition: (args["randomPosition"] === undefined) ? false : args["randomPosition"]
        };
    },
    flashback_oldFailSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_oldFailSmall)));
        return ecs.emotionResource(args);
    },
    you: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.you)));
        return ecs.trait(args);
    },
    distractTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.distractTowerConstruction)));
        return ecs.construction(args);
    },
    addOpinionExec: function(args){
        return {
            execute: addOpinionExec,
            opinionToAdd: (args["opinionToAdd"] === undefined) ? undefined : args["opinionToAdd"]
        };
    },
    needHelpGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needHelpGoal)));
        return ecs.worldGoal(args);
    },
    emotionResource: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        args["playerKillable"] = false;
        return {
            focusPathStopComponent: ecs.resourceFocusPathStopComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args)],
            focusTickResponseComponent: ecs.resourceFocusTickResponseComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            managedComponent: ecs.managedComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)].concat([ecs.emotionResourceDifficultyExec(args)]),
            junctionComponent: ecs.junctionComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killResourceCurrencies(args)],
            resourceComponent: ecs.resourceComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            loseControlExec: ecs.killEntity(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    openMenu: function(args){
        return {
            execute: openMenuExecute,
            markerKey: "openMenuMarker"
        };
    },
    tutorialUnpauseTextComponent: function(args){
        return {
            tutorialDone: tutorialUnpauseTutorialDone,
            nextEntities: (args["nextEntities"] === undefined) ? undefined : args["nextEntities"]
        };
    },
    building: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        return {
            managedComponent: ecs.managedComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)],
            junctionComponent: ecs.junctionComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    accuseSelfishMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.accuseSelfishMenu)));
        return ecs.goalCompleteMenu(args);
    },
    resourceButton: function(args){
        args["subPanel"] = (args["subPanel"] === undefined) ? "Towers" : args["subPanel"];
        args["multiTrait"] = (args["multiTrait"] === undefined) ? false : args["multiTrait"];
        return {
            interactionComponent: ecs.interactionComponent(args),
            uiActionComponent: ecs.buttonUiActionComponent(args),
            buttonControlComponent: ecs.towerControlComponent(args),
            createExecutables: [ecs.markTraitNew(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            uniqueComponent: (args.timeToDeath === undefined && !args.multiTrait) ? ecs.uniqueComponent(args) : undefined,
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            killExecutables: [ecs.killTowerButtonExec(args)],
            identityComponent: ecs.identityComponent(args)
        };
    },
    makeWorkWinMajorButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeWorkWinMajorButton)));
        return ecs.goalButton(args);
    },
    gameStageNotificationComponent: function(args){
        return {
            notificationFunctions: {goalComplete: checkStageComplete},
            serializeComponent: ecs.notificationSerializeComponent(args)
        };
    },
    meditation: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.meditation)));
        return ecs.currency(args);
    },
    takeSupportAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeSupportAction)));
        return ecs.currencyAction(args);
    },
    bulletTickComponent: function(args){
        return {
            tick: bulletTick
        };
    },
    calmnessMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmnessMineButton)));
        return ecs.resourceButton(args);
    },
    distractTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.distractTower)));
        return ecs.tower(args);
    },
    talkHappy: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkHappy)));
        return ecs.instantEmotionResource(args);
    },
    spendTimeGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeGoalConstruction)));
        return ecs.construction(args);
    },
    pathButton: function(args){
        return {
            rendererComponents: [ecs.pathButtonRenderComponent(args)]
        };
    },
    openResponseMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.openResponseMenu)));
        return ecs.goalCompleteMenu(args);
    },
    makeParticleEffect: function(args){
        if (args.particleKey === undefined){ throw "ECS fail " + args.key + " missing particleKey"; }
        return {
            particleKey: args['particleKey'],
            execute: makeParticleEffect
        };
    },
    acceptMeanlessMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.acceptMeanlessMenu)));
        return ecs.goalCompleteMenu(args);
    },
    currencyPath: function(args){
        return {
            currencyPathComponent: ecs.currencyPathComponent(args)
        };
    },
    pairTransformMarker: function(args){
        if (args.trait1 === undefined){ throw "ECS fail " + args.key + " missing trait1"; }
        if (args.trait2 === undefined){ throw "ECS fail " + args.key + " missing trait2"; }
        return {
            trait2: args['trait2'],
            tempKey: "tempTrait",
            trait1: args['trait1'],
            getReplaceKeys: pairTransformGetReplaceKeys
        };
    },
    setPanelComponent: function(args){
        return {
            panelButtons: [],
            expandPanel: expandPanel,
            minimized: false,
            canClose: false,
            closed: false,
            ignoreWhenMinimized: true
        };
    },
    pushInsecurityGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.pushInsecurityGoalConstruction)));
        return ecs.construction(args);
    },
    partnerInfoDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.partnerInfoDeposit)));
        return ecs.deposit(args);
    },
    searchingWorth: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.searchingWorth)));
        return ecs.trait(args);
    },
    getOverGoodWorkButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getOverGoodWorkButton)));
        return ecs.goalButton(args);
    },
    makeCriticismFlatMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeCriticismFlatMenu)));
        return ecs.goalCompleteMenu(args);
    },
    minorInterruptMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.minorInterruptMenu)));
        return ecs.goalCompleteMenu(args);
    },
    hisBadWorkToHisWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisBadWorkToHisWork)));
        return ecs.transformExec(args);
    },
    forceOpennessMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.forceOpennessMenu)));
        return ecs.goalCompleteMenu(args);
    },
    swallowOpinionComponent: function(args){
        return {
            previousOpinions: undefined
        };
    },
    carriageComponent: function(args){
        return {
            direction: 0,
            holding: []
        };
    },
    obsessHimAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessHimAction)));
        return ecs.currencyAction(args);
    },
    himSupportMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.himSupportMenu)));
        return ecs.goalCompleteMenu(args);
    },
    descriptionComponent: function(args){
        return {
            description: (args["description"] === undefined) ? "" : args["description"]
        };
    },
    restlessToHisWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.restlessToHisWork)));
        return ecs.transformExec(args);
    },
    workTopic: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.workTopic)));
        return ecs.currency(args);
    },
    will: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.will)));
        return ecs.currency(args);
    },
    openMenuClickComponent: function(args){
        return {
            onClick: openMenuOnClick
        };
    },
    cleverPathRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.cleverPathRelationship)));
        return ecs.pathMaker(args);
    },
    reachOutButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reachOutButton)));
        return ecs.goalButton(args);
    },
    truthButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.truthButton)));
        return ecs.towerButton(args);
    },
    needHelpMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needHelpMenu)));
        return ecs.goalCompleteMenu(args);
    },
    overcomeCrisisButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.overcomeCrisisButton)));
        return ecs.goalButton(args);
    },
    killLostControlExec: function(args){
        return {
            execute: killLostControlExec
        };
    },
    openUpBranch: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.openUpBranch)));
        return ecs.flagBranch(args);
    },
    obsessHimTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessHimTower)));
        return ecs.tower(args);
    },
    makeOldFailFlatGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeOldFailFlatGoalConstruction)));
        return ecs.construction(args);
    },
    indulgeViceGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.indulgeViceGoal)));
        return ecs.worldGoal(args);
    },
    strong: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.strong)));
        return ecs.trait(args);
    },
    giveInGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.giveInGoalConstruction)));
        return ecs.construction(args);
    },
    complimentButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentButton)));
        return ecs.towerButton(args);
    },
    meditativeMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.meditativeMineButton)));
        return ecs.resourceButton(args);
    },
    memoryTowerButtonIssacEntityComponent: function(args){
        return {
            endLifecycle: trueFunction,
            startLifecycle: makeIsaacLifecycleEntities,
            makeLifecycleEntities: makeLifecycleEntities,
            entitiesMade: [],
            isaacEntities: (args["isaacEntities"] === undefined) ? [] : args["isaacEntities"]
        };
    },
    timedMakeEntities: function(args){
        return {
            execute: timedMakeEntities,
            timedOutEntities: (args["timedOutEntities"] === undefined) ? [] : args["timedOutEntities"]
        };
    },
    selfExtensionComponent: function(args){
        return {
            emotion: undefined,
            setEmotion: selfExtensionSetEmotion,
            emotionLife: 0
        };
    },
    thinkMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.thinkMineButton)));
        return ecs.resourceButton(args);
    },
    social: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.social)));
        return ecs.currency(args);
    },
    viceFlatYouMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.viceFlatYouMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    criticismFlat: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismFlat)));
        return ecs.instantEmotionResource(args);
    },
    timedDifficultyModifyExec: function(args){
        return {
            execute: timedDifficultyModify
        };
    },
    minorInterruptGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.minorInterruptGoal)));
        return ecs.worldGoal(args);
    },
    meditativeMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.meditativeMineConstruction)));
        return ecs.construction(args);
    },
    damageIndicatorRenderComponent: function(args){
        if (args.sourceId === undefined){ throw "ECS fail " + args.key + " missing sourceId"; }
        return {
            priority: 12,
            sourceId: args['sourceId'],
            renderState: "default",
            render: damageIndicatorRender
        };
    },
    deriveWorkTopicGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.deriveWorkTopicGoalConstruction)));
        return ecs.construction(args);
    },
    executable: function(args){
        if (args.execute === undefined){ throw "ECS fail " + args.key + " missing execute"; }
        return {
            execute: args['execute']
        };
    },
    sourceLifeSentinelComponent: function(args){
        if (args.sourceId === undefined){ throw "ECS fail " + args.key + " missing sourceId"; }
        return {
            sourceId: args['sourceId'],
            checkAlive: checkParticleEffectAlive
        };
    },
    helpInfoPanel: function(args){
        args["size"] = [width, 678];
        return {
            rendererComponents: [ecs.helpInfoPanelRenderComponent(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            panelComponent: ecs.panelComponent(args),
            pauseComponent: ecs.pauseComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    conversation_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.conversation_ext)));
        return ecs.sourceExtension(args);
    },
    niceMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.niceMenu)));
        return ecs.goalCompleteMenu(args);
    },
    memory_worthlessFeel: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_worthlessFeel)));
        return ecs.memory(args);
    },
    memoryTickComponent: function(args){
        return {
            lastManagedCount: 0,
            tick: memoryTick
        };
    },
    helpValueTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpValueTower)));
        return ecs.tower(args);
    },
    makeCriticismSwarmMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeCriticismSwarmMenu)));
        return ecs.goalCompleteMenu(args);
    },
    casualSwarmHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.casualSwarmHim)));
        return ecs.instantEmotionResource(args);
    },
    calmPartnerGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmPartnerGoal)));
        return ecs.worldGoal(args);
    },
    personTowerButton: function(args){
        args["subPanel"] = (args["subPanel"] === undefined) ? "Towers" : args["subPanel"];
        args["multiTrait"] = (args["multiTrait"] === undefined) ? false : args["multiTrait"];
        return {
            healthComponent: ecs.singleHealthComponent(args),
            uiActionComponent: ecs.buttonUiActionComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            buttonControlComponent: ecs.towerControlComponent(args),
            personHeldComponent: ecs.personHeldComponent(args),
            createExecutables: [ecs.markTraitNew(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            killExecutables: [ecs.killTowerButtonExec(args)],
            descriptionComponent: ecs.descriptionComponent(args),
            uniqueComponent: (args.timeToDeath === undefined && !args.multiTrait) ? ecs.uniqueComponent(args) : undefined,
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    impulse: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.impulse)));
        return ecs.currency(args);
    },
    complimentTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentTowerConstruction)));
        return ecs.construction(args);
    },
    constructionClickComponent: function(args){
        return {
            onClick: constructOnClick
        };
    },
    spendTimeMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeMenu)));
        return ecs.goalCompleteMenu(args);
    },
    uiClickComponent: function(args){
        return {
            uiClick: (args["uiClick"] === undefined) ? args['trueFunction'] : args["uiClick"]
        };
    },
    explodeTrait: function(args){
        return {
            emotionKeys: ["worthlessHim", "stupidityFlat"],
            execute: args['execute'],
            traitToExplode: "faithCrisis",
            explodeTraitExec: explodeTraitExec
        };
    },
    takeConnectMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeConnectMenu)));
        return ecs.goalCompleteMenu(args);
    },
    pathVelocityComponent: function(args){
        return {
            velocity: 1,
            isMoving: false,
            ticks: 0,
            isHeld: false,
            chosenPath: false
        };
    },
    startRelationHimButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startRelationHimButton)));
        return ecs.goalButton(args);
    },
    quietCriticismMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.quietCriticismMenu)));
        return ecs.goalCompleteMenu(args);
    },
    completeWorkGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.completeWorkGoal)));
        return ecs.worldGoal(args);
    },
    makeStupidityFlatGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeStupidityFlatGoalConstruction)));
        return ecs.construction(args);
    },
    tryForConnectionYouGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryForConnectionYouGoal)));
        return ecs.worldGoal(args);
    },
    busyWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.busyWork)));
        return ecs.currency(args);
    },
    interactionComponent: function(args){
        return {
            connectionKeys: [],
            interactionKeys: (args["interactionKeys"] === undefined) ? PARAMETERS.interactionKeys : args["interactionKeys"],
            canInteractSelf: canInteractSelf,
            canInteract: canInteract
        };
    },
    qualityImprovement: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            personHeldComponent: (args.qualityEntity === undefined) ? ecs.personHeldComponent(args) : undefined,
            createExecutables: [ecs.improveQualityExec(args), ecs.killEntity(args)]
        };
    },
    getFeedbackButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getFeedbackButton)));
        return ecs.goalButton(args);
    },
    makeSlowWorkSwarmGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeSlowWorkSwarmGoal)));
        return ecs.worldGoal(args);
    },
    connectHurtGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.connectHurtGoal)));
        return ecs.worldGoal(args);
    },
    allowWeaknessGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.allowWeaknessGoal)));
        return ecs.worldGoal(args);
    },
    getOverBadWorkMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getOverBadWorkMenu)));
        return ecs.goalCompleteMenu(args);
    },
    menuModifier: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            menuModifierComponent: ecs.menuModifierComponent(args)
        };
    },
    focusRenderComponent: function(args){
        return {
            priority: 9,
            renderState: "default",
            render: focusRender
        };
    },
    makeOnCreateEntityExec: function(args){
        args["makeOnCreateEntities"] = (args["makeOnCreateEntities"] === undefined) ? [] : args["makeOnCreateEntities"];
        return {
            execute: executeMakeEntities,
            entitiesToMake: args['makeOnCreateEntities'],
            adjacent: (args["adjacent"] === undefined) ? false : args["adjacent"]
        };
    },
    slowWorkSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.slowWorkSmall)));
        return ecs.creep(args);
    },
    makeCriticismSwarmButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeCriticismSwarmButton)));
        return ecs.goalButton(args);
    },
    memoryResourceButton: function(args){
        args["managerKey"] = args.sourceKey;
        args["multiTrait"] = true;
        args["subPanel"] = (args["subPanel"] === undefined) ? "Towers" : args["subPanel"];
        args["multiTrait"] = (args["multiTrait"] === undefined) ? false : args["multiTrait"];
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        return {
            interactionComponent: ecs.interactionComponent(args),
            uiActionComponent: ecs.buttonUiActionComponent(args),
            buttonControlComponent: ecs.towerControlComponent(args),
            createExecutables: [ecs.markTraitNew(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            uniqueComponent: (args.timeToDeath === undefined && !args.multiTrait) ? ecs.uniqueComponent(args) : undefined,
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            killExecutables: [ecs.killTowerButtonExec(args)],
            identityComponent: ecs.identityComponent(args)
        };
    },
    memoryFadeExec: function(args){
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        if (args.newTrait === undefined){ throw "ECS fail " + args.key + " missing newTrait"; }
        return {
            execute: memoryFadeExec,
            sourceKey: args['sourceKey'],
            newTrait: args['newTrait']
        };
    },
    calmnessDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmnessDeposit)));
        return ecs.deposit(args);
    },
    makeAllReplaceMarker: function(args){
        if (args.csv === undefined){ throw "ECS fail " + args.key + " missing csv"; }
        return {
            csv: args['csv'],
            getReplaceKeys: makeAllGetReplaceKeys
        };
    },
    fishComplimentsButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.fishComplimentsButton)));
        return ecs.goalButton(args);
    },
    toastNotificationComponent: function(args){
        return {
            notificationFunctions: simpleDict(PARAMETERS.infoPanel, toastNotification)
        };
    },
    personKillExec: function(args){
        return {
            execute: personKillExec
        };
    },
    buildPanel: function(args){
        return {
            panelComponent: ecs.setPanelComponent(args),
            absolutePositionComponent: ecs.buildPanelAbsolutePositionComponent(args),
            rendererComponents: [ecs.buildPanelRenderComponent(args)],
            uiClickComponent: ecs.panelUiClickComponent(args)
        };
    },
    clever_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.clever_ext)));
        return ecs.sourceExtension(args);
    },
    restlessPathStrong: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.restlessPathStrong)));
        return ecs.pathMaker(args);
    },
    criticizeSelfMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticizeSelfMenu)));
        return ecs.goalCompleteMenu(args);
    },
    completeWorkMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.completeWorkMenu)));
        return ecs.goalCompleteMenu(args);
    },
    openResponseGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.openResponseGoal)));
        return ecs.worldGoal(args);
    },
    talkInterestingGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkInterestingGoal)));
        return ecs.worldGoal(args);
    },
    emotionResourceMapComponent: function(args){
        if (args.emotionToMap === undefined){ throw "ECS fail " + args.key + " missing emotionToMap"; }
        if (args.emotionMappedEntities === undefined){ throw "ECS fail " + args.key + " missing emotionMappedEntities"; }
        return {
            emotionMappedEntities: args['emotionMappedEntities'],
            startManagedEntities: (args["startManagedEntities"] === undefined) ? [] : args["startManagedEntities"],
            emotionToMap: args['emotionToMap']
        };
    },
    hurting: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hurting)));
        return ecs.trait(args);
    },
    good: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.good)));
        return ecs.trait(args);
    },
    calmPartnerMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmPartnerMenu)));
        return ecs.goalCompleteMenu(args);
    },
    trackActionables: function(args){
        return {
            execute: trackActionables
        };
    },
    resourceComponent: function(args){
        if (args.resourceKeys === undefined){ throw "ECS fail " + args.key + " missing resourceKeys"; }
        return {
            resourceCount: (args["resourceCount"] === undefined) ? undefined : args["resourceCount"],
            ticks: 2,
            impulseTicks: 10,
            currenciesAtResource: currenciesAtResource,
            resourceKeys: args['resourceKeys'],
            resourceEntities: (args["resourceEntities"] === undefined) ? undefined : args["resourceEntities"]
        };
    },
    towerFlash: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            rendererComponents: [ecs.towerFlashRenderComponent(args)],
            positionComponent: ecs.positionComponent(args)
        };
    },
    makeSlowWorkSwarmMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeSlowWorkSwarmMenu)));
        return ecs.goalCompleteMenu(args);
    },
    focusMakingComponent: function(args){
        if (args.focusCount === undefined){ throw "ECS fail " + args.key + " missing focusCount"; }
        return {
            ai: (args["ai"] === undefined) ? false : args["ai"],
            ticks: 2,
            focusEfficiency: focusEfficiency,
            impulseTicks: 22,
            focusCount: args['focusCount'],
            focusUsing: 0
        };
    },
    selfValueButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfValueButton)));
        return ecs.towerButton(args);
    },
    trainPathMakerHighlightRenderComponent: function(args){
        return {
            priority: 10,
            highlightImage: "activeOutline",
            renderState: "default",
            render: trainPathMakerHighlightRender,
            timeToBlink: 0.25
        };
    },
    tryForConnectionHimButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryForConnectionHimButton)));
        return ecs.goalButton(args);
    },
    majorAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.majorAction)));
        return ecs.currencyAction(args);
    },
    jealousyBurstMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.jealousyBurstMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    flirtHimGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtHimGoal)));
        return ecs.worldGoal(args);
    },
    swarmAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.swarmAction)));
        return ecs.currencyAction(args);
    },
    newTraitParticle: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.newTraitParticle)));
        return ecs.traitParticleEffect(args);
    },
    allBuildingPanel: function(args){
        args["y"] = 5;
        args["x"] = (width - 800) / 2;
        args["key"] = PARAMETERS.allBuildingPanel;
        args["size"] = [800, 300];
        return {
            rendererComponents: [ecs.allBuildingPanelRenderComponent(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            panelComponent: ecs.panelComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    createModifyEntity: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            createModifyComponent: ecs.createModifyComponent(args)
        };
    },
    killCurrencyExec: function(args){
        if (args.currencyToKill === undefined){ throw "ECS fail " + args.key + " missing currencyToKill"; }
        return {
            currencyToKill: args['currencyToKill'],
            execute: killCurrencyExec
        };
    },
    casualMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.casualMed)));
        return ecs.creep(args);
    },
    restless: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.restless)));
        return ecs.trait(args);
    },
    menuTutorialTextRenderComponent: function(args){
        return {
            shownOnce: false,
            render: menuTutorialTextRender,
            text: args['text'],
            menuEntity: undefined,
            yOffset: (args["yOffset"] === undefined) ? 0 : args["yOffset"],
            priority: 24,
            entityToMark: args['entityToMark'],
            renderState: "default",
            shouldDrawArrow: (args["shouldDrawArrow"] === undefined) ? true : args["shouldDrawArrow"],
            hasDrawn: false,
            drawArrow: tutorialTextDrawArrow,
            xOffset: (args["xOffset"] === undefined) ? 100 : args["xOffset"]
        };
    },
    killPersonGoals: function(args){
        return {
            execute: killPersonGoals
        };
    },
    currencyAction: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args),
            currencyActionComponent: ecs.currencyActionComponent(args)
        };
    },
    getOverGoodWorkGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getOverGoodWorkGoalConstruction)));
        return ecs.construction(args);
    },
    warmPathRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.warmPathRelationship)));
        return ecs.pathMaker(args);
    },
    distractButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.distractButton)));
        return ecs.towerButton(args);
    },
    selfValuePlaced: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfValuePlaced)));
        return ecs.placedTower(args);
    },
    flagBranch: function(args){
        return {
            replaceMarker: ecs.flagBranchReplaceMarker(args)
        };
    },
    makeCriticismFlatGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeCriticismFlatGoal)));
        return ecs.worldGoal(args);
    },
    randomIfNoneReplaceMarker: function(args){
        if (args.keys === undefined){ throw "ECS fail " + args.key + " missing keys"; }
        return {
            keys: args['keys'],
            getReplaceKeys: randomIfNoneGetReplaceKeys
        };
    },
    exploreNewResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.exploreNewResult)));
        return ecs.randomReplace(args);
    },
    willMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.willMineButton)));
        return ecs.resourceButton(args);
    },
    flashback_oldFailMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_oldFailMed)));
        return ecs.emotionResource(args);
    },
    personHeldComponent: function(args){
        return {
            personHeld: (args["personHeld"] === undefined) ? undefined : args["personHeld"]
        };
    },
    steamAchievement: function(args){
        return {
            steamAchievementComponent: ecs.steamAchievementComponent(args),
            notificationComponents: [ecs.steamAchievementNotificationComponent(args)]
        };
    },
    imageRenderComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            priority: 6,
            image: args['image'],
            renderState: "default",
            render: imageRender
        };
    },
    spendTimeButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeButton)));
        return ecs.goalButton(args);
    },
    randomIfNone: function(args){
        return {
            replaceMarker: ecs.randomIfNoneReplaceMarker(args)
        };
    },
    complimentMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentMed)));
        return ecs.creep(args);
    },
    emotionResourceDifficultyExec: function(args){
        return {
            execute: emotionResourceDifficultyExec
        };
    },
    solveProbeTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.solveProbeTower)));
        return ecs.tower(args);
    },
    helpMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpMenu)));
        return ecs.goalCompleteMenu(args);
    },
    reinforceComplimentGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reinforceComplimentGoal)));
        return ecs.worldGoal(args);
    },
    makeSlowWorkFlatMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeSlowWorkFlatMenu)));
        return ecs.goalCompleteMenu(args);
    },
    rejectMeanlessButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.rejectMeanlessButton)));
        return ecs.goalButton(args);
    },
    dreamDeathLarge: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.dreamDeathLarge)));
        return ecs.creep(args);
    },
    exploreStrengthGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.exploreStrengthGoal)));
        return ecs.worldGoal(args);
    },
    entityManagerComponent: function(args){
        return {
            findFreeManagedSpace: findFreeManagedSpace,
            disabled: false,
            hasNew: false,
            checkForNewManaged: checkForNewManaged,
            canMakeManagedEntity: canMakeManagedEntity
        };
    },
    tutorialTextRenderComponent: function(args){
        if (args.entityToMark === undefined){ throw "ECS fail " + args.key + " missing entityToMark"; }
        if (args.text === undefined){ throw "ECS fail " + args.key + " missing text"; }
        return {
            render: tutorialTextRender,
            text: args['text'],
            yOffset: (args["yOffset"] === undefined) ? 0 : args["yOffset"],
            priority: 24,
            entityToMark: args['entityToMark'],
            renderState: "default",
            drawArrow: tutorialTextDrawArrow,
            xOffset: (args["xOffset"] === undefined) ? 100 : args["xOffset"]
        };
    },
    makeEntityComponent: function(args){
        return {
            execute: executeMakeEntities,
            entitiesToMake: (args["entitiesToMake"] === undefined) ? [] : args["entitiesToMake"],
            adjacent: (args["adjacent"] === undefined) ? false : args["adjacent"]
        };
    },
    askForBeliefButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askForBeliefButton)));
        return ecs.goalButton(args);
    },
    takeSupportButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeSupportButton)));
        return ecs.towerButton(args);
    },
    solveProbeAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.solveProbeAction)));
        return ecs.currencyAction(args);
    },
    swarm: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.swarm)));
        return ecs.currency(args);
    },
    becomeCriticalMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.becomeCriticalMenu)));
        return ecs.goalCompleteMenu(args);
    },
    personGoalButton: function(args){
        args["managerKey"] = args.personHeld;
        args["subPanel"] = (args["subPanel"] === undefined) ? "Goals" : args["subPanel"];
        return {
            uiActionComponent: ecs.buttonUiActionComponent(args),
            buttonControlComponent: ecs.goalButtonControlComponent(args),
            personHeldComponent: ecs.personHeldComponent(args),
            createExecutables: [ecs.killIfFlagExec(args), ecs.markTraitNew(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    qualityComponent: function(args){
        if (args.quality === undefined){ throw "ECS fail " + args.key + " missing quality"; }
        return {
            quality: args['quality']
        };
    },
    relationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.relationship)));
        return ecs.trait(args);
    },
    giveInGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.giveInGoal)));
        return ecs.worldGoal(args);
    },
    defineRole: function(args){
        return {
            replaceMarker: ecs.defineRoleReplaceMarker(args)
        };
    },
    focusPathStopComponent: function(args){
        return {
            interactWithTrain: falseFunction,
            currenciesNeededAtPoint: (args["currenciesNeededAtPoint"] === undefined) ? emptyArrayFunction : args["currenciesNeededAtPoint"],
            currenciesMadeAtPoint: (args["currenciesMadeAtPoint"] === undefined) ? emptyArrayFunction : args["currenciesMadeAtPoint"],
            isDisabled: false,
            currenciesExistAtPoint: currenciesExistAtPoint,
            updateCurrencyDictWithStop: updateCurrencyDictWithStop,
            isPathEnd: (args["isPathEnd"] === undefined) ? false : args["isPathEnd"],
            checkFocusStopDisabled: checkFocusStopDisabled,
            requiredOpinions: (args["requiredOpinions"] === undefined) ? [] : args["requiredOpinions"],
            enableChecks: (args["enableChecks"] === undefined) ? [] : args["enableChecks"]
        };
    },
    workWinDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.workWinDeposit)));
        return ecs.deposit(args);
    },
    dailyEntityDayResponseComponent: function(args){
        return {
            dayStart: dailyEntityMake
        };
    },
    askAboutRestlessGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askAboutRestlessGoal)));
        return ecs.worldGoal(args);
    },
    trainPathWarningRender: function(args){
        return {
            priority: 11,
            renderState: "default",
            render: trainPathWarningRender
        };
    },
    getOverGoodWorkGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getOverGoodWorkGoal)));
        return ecs.worldGoal(args);
    },
    whatsNewMaker: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.whatsNewMaker)));
        return ecs.dailyEntityMaker(args);
    },
    obsessGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessGoalConstruction)));
        return ecs.construction(args);
    },
    completeWorkGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.completeWorkGoalConstruction)));
        return ecs.construction(args);
    },
    makeAllPathMaker: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeAllPathMaker)));
        return ecs.makeAll(args);
    },
    diveHurtGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.diveHurtGoalConstruction)));
        return ecs.construction(args);
    },
    supportNeedButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportNeedButton)));
        return ecs.towerButton(args);
    },
    qualityResourceTickComponent: function(args){
        if (args.qualityThreshold === undefined){ throw "ECS fail " + args.key + " missing qualityThreshold"; }
        if (args.highQualityResources === undefined){ throw "ECS fail " + args.key + " missing highQualityResources"; }
        return {
            tick: qualityResourceTick,
            qualityThreshold: args['qualityThreshold'],
            highQualityResources: args['highQualityResources'],
            flipEntities: (args["flipEntities"] === undefined) ? [] : args["flipEntities"],
            lastQuality: args['quality'],
            lowQualityResources: args['resourceKeys']
        };
    },
    selfValueAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfValueAction)));
        return ecs.currencyAction(args);
    },
    newParticle: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.newParticle)));
        return ecs.worldGoalParticleEffect(args);
    },
    workerRenderComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            priority: 12,
            image: args['image'],
            renderState: "default",
            render: currencyRender,
            renderPos: undefined
        };
    },
    experienceTrigger: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            experienceTriggerComponent: ecs.experienceTriggerComponent(args)
        };
    },
    self: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.self)));
        return ecs.source(args);
    },
    sourceExtensionClickComponent: function(args){
        return {
            onClick: sourceExtensionOnClick
        };
    },
    triggerCrisisButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.triggerCrisisButton)));
        return ecs.goalButton(args);
    },
    becomeCriticalGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.becomeCriticalGoal)));
        return ecs.worldGoal(args);
    },
    newRelationshipToRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.newRelationshipToRelationship)));
        return ecs.transformExec(args);
    },
    criticismTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismTowerConstruction)));
        return ecs.construction(args);
    },
    needHelpButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needHelpButton)));
        return ecs.goalButton(args);
    },
    findHelpGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findHelpGoal)));
        return ecs.worldGoal(args);
    },
    complimentFlatYouMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentFlatYouMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    acceptMeanlessGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.acceptMeanlessGoal)));
        return ecs.worldGoal(args);
    },
    beBelievedInMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.beBelievedInMenu)));
        return ecs.goalCompleteMenu(args);
    },
    junctionRenderComponent: function(args){
        return {
            priority: 12,
            renderState: "default",
            render: junctionRender
        };
    },
    relationshipPathStrong: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.relationshipPathStrong)));
        return ecs.pathMaker(args);
    },
    constructionRenderComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            priority: 8,
            outlineImage: false,
            render: constructionRender,
            wobble: 0,
            image: args['image'],
            timeDrawn: 0,
            dustImage: "dust",
            scaleTime: 0.15,
            getWobble: getWobble,
            renderState: "default",
            renderTrainIcon: renderTrainIcon,
            outlineTime: 0
        };
    },
    social_clever: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.social_clever)));
        return ecs.currency(args);
    },
    slowWorkDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.slowWorkDeposit)));
        return ecs.deposit(args);
    },
    revertMemory: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.revertMemoryExec(args), ecs.killEntity(args)]
        };
    },
    helpHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpHim)));
        return ecs.currency(args);
    },
    toughTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.toughTower)));
        return ecs.tower(args);
    },
    giveInMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.giveInMenu)));
        return ecs.goalCompleteMenu(args);
    },
    searchingWorth_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.searchingWorth_ext)));
        return ecs.sourceExtension(args);
    },
    emotionTickModifier: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            emotionTickModifyComponent: ecs.emotionTickModifyComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    majorTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.majorTowerConstruction)));
        return ecs.construction(args);
    },
    memory_jealousyBurst: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_jealousyBurst)));
        return ecs.memory(args);
    },
    relationshipTime: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.relationshipTime)));
        return ecs.currency(args);
    },
    trainPathMakerTickComponent: function(args){
        return {
            tick: trainPathMakerTick
        };
    },
    flaggedMake: function(args){
        return {
            replaceMarker: ecs.flaggedMakeReplaceMarker(args)
        };
    },
    acceptConnectionYouGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.acceptConnectionYouGoal)));
        return ecs.worldGoal(args);
    },
    takeSupportTowerPlaced: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeSupportTowerPlaced)));
        return ecs.placedTower(args);
    },
    hisGoodWorkToHisWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisGoodWorkToHisWork)));
        return ecs.transformExec(args);
    },
    interruptSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.interruptSmall)));
        return ecs.creep(args);
    },
    him: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.him)));
        return ecs.trait(args);
    },
    flirtButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtButton)));
        return ecs.towerButton(args);
    },
    goodnessMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goodnessMineConstruction)));
        return ecs.construction(args);
    },
    risingText: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            rendererComponents: [ecs.risingTextRenderComponent(args)]
        };
    },
    opennessDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.opennessDeposit)));
        return ecs.deposit(args);
    },
    activity: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.activity)));
        return ecs.currency(args);
    },
    jealousyBurstMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.jealousyBurstMine)));
        return ecs.emotionResource(args);
    },
    uiActionComponent: function(args){
        return {
            getUiActions: getUiActions,
            generateUiActions: (args["generateUiActions"] === undefined) ? undefined : args["generateUiActions"],
            memoizedActions: undefined
        };
    },
    connectHurtGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.connectHurtGoalConstruction)));
        return ecs.construction(args);
    },
    connectFriendsMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.connectFriendsMenu)));
        return ecs.goalCompleteMenu(args);
    },
    oldHurt: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldHurt)));
        return ecs.emotionSource(args);
    },
    trainPathMakingPanelRender: function(args){
        return {
            insetColor: "#000000",
            completeFunction: undefined,
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "uiBack",
            killStopFunctions: [],
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            trainIcon: "trainIcon",
            priority: 18,
            render: trainPathMakingPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            blinkTime: 0.9,
            specificRender: args['specificRender'],
            drawHelpButton: drawHelpButton
        };
    },
    gainControl_joy: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.gainControl_joy)));
        return ecs.gainControlMenu(args);
    },
    tempTrait_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tempTrait_ext)));
        return ecs.sourceExtension(args);
    },
    talkInterestingGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkInterestingGoalConstruction)));
        return ecs.construction(args);
    },
    worthless_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worthless_ext)));
        return ecs.sourceExtension(args);
    },
    compliment: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.compliment)));
        return ecs.currency(args);
    },
    trainPathCircRenderComponent: function(args){
        return {
            priority: 12,
            renderTime: 0,
            renderState: "default",
            render: trainPathCircRender
        };
    },
    makeOldFailSwarmGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeOldFailSwarmGoal)));
        return ecs.worldGoal(args);
    },
    painMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.painMine)));
        return ecs.memoryResource(args);
    },
    trainPanel: function(args){
        args["x"] = width - 300;
        args["size"] = [300, 400];
        args["size"] = (args["size"] === undefined) ? [550, 450] : args["size"];
        return {
            rendererComponents: [ecs.trainPanelRenderComponent(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            helpPanelComponent: ecs.helpPanelComponent(args),
            panelComponent: ecs.entityPanelComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    spendTimeWarmButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeWarmButton)));
        return ecs.goalButton(args);
    },
    towerFlashRenderComponent: function(args){
        return {
            priority: 6,
            images: ["border0", "border1", "border2"],
            renderState: "default",
            timeToDeath: 0.5,
            render: towerFlashRender
        };
    },
    personGoalTrackComponent: function(args){
        return {
            successExecutables: [ecs.goalCompleteExec(args)].concat([ecs.trackActionables(args), ecs.makeEntityComponent(args), ecs.makeGoalMenuExecutable(args)]).concat([ecs.addOpinionExec(args)]),
            checkCompleted: checkWorldGoalComponent
        };
    },
    currencyBoostComponent: function(args){
        return {
            currencyBoost: (args["currencyBoost"] === undefined) ? {} : args["currencyBoost"]
        };
    },
    focusPanelRenderComponent: function(args){
        return {
            insetColor: "#000000",
            showFocusPanel: undefined,
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "opaqueBack",
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            priority: 19,
            render: focusPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            toggleFocusPath: undefined,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            specificRender: args['specificRender'],
            drawHelpButton: drawHelpButton
        };
    },
    exploreStrengthMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.exploreStrengthMenu)));
        return ecs.goalCompleteMenu(args);
    },
    makeOldFailFlatGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeOldFailFlatGoal)));
        return ecs.worldGoal(args);
    },
    appreciateWorkGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.appreciateWorkGoal)));
        return ecs.worldGoal(args);
    },
    traitPanel: function(args){
        args["size"] = [740, 500];
        args["size"] = (args["size"] === undefined) ? [550, 450] : args["size"];
        return {
            rendererComponents: [ecs.traitPanelRenderComponent(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            helpPanelComponent: ecs.helpPanelComponent(args),
            panelComponent: ecs.entityPanelComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    selfishnessMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfishnessMine)));
        return ecs.resource(args);
    },
    disableTrait: function(args){
        return {
            disableTraitComponent: ecs.disableTraitComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined
        };
    },
    himSupportTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.himSupportTower)));
        return ecs.tower(args);
    },
    thinkMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.thinkMine)));
        return ecs.resource(args);
    },
    openness: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.openness)));
        return ecs.currency(args);
    },
    gameStage: function(args){
        return {
            createExecutables: [ecs.makeOnCreateEntityExec(args)],
            stageChangeComponent: ecs.stageChangeComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            dayResponseComponent: ecs.gameStageDayResponseComponent(args),
            notificationComponents: [ecs.gameStageNotificationComponent(args)]
        };
    },
    worthless: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worthless)));
        return ecs.trait(args);
    },
    feedCrisisButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.feedCrisisButton)));
        return ecs.goalButton(args);
    },
    beHelpMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.beHelpMenu)));
        return ecs.goalCompleteMenu(args);
    },
    randomMenuMarker: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            randomMenuComponent: ecs.randomMenuComponent(args)
        };
    },
    noFocusNotifier: function(args){
        return {
            rendererComponents: [ecs.noFocusNotifierRenderComponent(args)]
        };
    },
    wishMakingComponent: function(args){
        if (args.makeWish === undefined){ throw "ECS fail " + args.key + " missing makeWish"; }
        if (args.canMakeWish === undefined){ throw "ECS fail " + args.key + " missing canMakeWish"; }
        return {
            makeWish: args['makeWish'],
            canMakeWish: args['canMakeWish']
        };
    },
    selfExtensionTickComponent: function(args){
        return {
            tick: selfExtensionTick
        };
    },
    needPainButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needPainButton)));
        return ecs.memoryTowerButton(args);
    },
    makeSlowWorkFlatGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeSlowWorkFlatGoal)));
        return ecs.worldGoal(args);
    },
    worldGoalComponent: function(args){
        if (args.currencyRequested === undefined){ throw "ECS fail " + args.key + " missing currencyRequested"; }
        return {
            goalSeen: false,
            requestingCurrency: false,
            currencyRequested: args['currencyRequested'],
            origCurrencyRequested: _.clone(args.currencyRequested)
        };
    },
    connectHurtDone: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.connectHurtDone)));
        return ecs.endGoal(args);
    },
    getOverBadWorkGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getOverBadWorkGoal)));
        return ecs.worldGoal(args);
    },
    healthComponent: function(args){
        if (args.health === undefined){ throw "ECS fail " + args.key + " missing health"; }
        return {
            kill: killHealthComponent,
            damageFactor: (args["damageFactor"] === undefined) ? 1 : args["damageFactor"],
            health: args['health'],
            maxHealth: args['health']
        };
    },
    blinkTrainStops: function(args){
        return {
            execute: blinkTrainStopsExec,
            image: "activeOutline-0099ff"
        };
    },
    selfDistractionTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfDistractionTower)));
        return ecs.tower(args);
    },
    defineHelpGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.defineHelpGoal)));
        return ecs.worldGoal(args);
    },
    traitParticleEffect: function(args){
        args["impulseTimeToCheck"] = (args["impulseTimeToCheck"] === undefined) ? 0.1 : args["impulseTimeToCheck"];
        args["startParticles"] = (args["startParticles"] === undefined) ? 10 : args["startParticles"];
        return {
            healthComponent: ecs.singleHealthComponent(args),
            lifeSentinelComponent: ecs.traitParticleEffectLifeSentinelComponent(args),
            rendererComponents: [ecs.particleEffectRenderComponent(args)]
        };
    },
    takeStrengthMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeStrengthMenu)));
        return ecs.goalCompleteMenu(args);
    },
    caringTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.caringTowerConstruction)));
        return ecs.construction(args);
    },
    findUsefulMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findUsefulMenu)));
        return ecs.goalCompleteMenu(args);
    },
    defineRoleBranch: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.defineRoleBranch)));
        return ecs.flagBranch(args);
    },
    feelUselessButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.feelUselessButton)));
        return ecs.goalButton(args);
    },
    flashback_casualSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_casualSmall)));
        return ecs.emotionResource(args);
    },
    junctionComponent: function(args){
        return {
            heldItems: [],
            junctionItemForKey: junctionItemForKey
        };
    },
    crisisExplode: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.explodeTrait(args)]
        };
    },
    supportTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportTowerConstruction)));
        return ecs.memoryConstruction(args);
    },
    memory_complimentFlatYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_complimentFlatYou)));
        return ecs.memory(args);
    },
    aloneFlatHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.aloneFlatHim)));
        return ecs.instantEmotionResource(args);
    },
    exploreNewGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.exploreNewGoal)));
        return ecs.worldGoal(args);
    },
    allTrainPanelRenderComponent: function(args){
        return {
            insetColor: "#000000",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "uiBack",
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            priority: 18,
            render: outPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            specificRender: allTrainPanelRender,
            drawHelpButton: drawHelpButton
        };
    },
    spendTimeWarmGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeWarmGoal)));
        return ecs.worldGoal(args);
    },
    clearTrait: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.clearTraitExec(args), ecs.killEntity(args)]
        };
    },
    openUpMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.openUpMenu)));
        return ecs.goalCompleteMenu(args);
    },
    person: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.person)));
        args["touchable"] = true;
        args["health"] = (args["health"] === undefined) ? 2000 : args["health"];
        args["panelKey"] = (args["panelKey"] === undefined) ? PARAMETERS.traitPanel : args["panelKey"];
        return {
            uiActionComponent: ecs.buildingUiActionComponent(args),
            experienceComponent: ecs.experienceComponent(args),
            createExecutables: [ecs.builtSourceCreateExec(args), ecs.makeExtraPathsExec(args)].concat([ecs.personCreateExec(args)]),
            uiDataComponent: ecs.uiDataComponent(args),
            entityManagerComponent: ecs.entityManagerComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            isaacEntityComponent: ecs.isaacEntityComponent(args),
            rendererComponents: [ecs.builtSourceRendererComponent(args)],
            focusTickResponseComponent: (args.aliveEntities) ? ecs.focusTickAliveMakerComponent(args) : undefined,
            menuCloseComponent: ecs.traitMenuCloseComponent(args),
            personHeldComponent: (args.personHeld) ? ecs.personHeldComponent(args) : undefined,
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killExtensions(args)].concat([ecs.personKillExec(args)]),
            healthComponent: ecs.healthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            positionComponent: ecs.positionComponent(args),
            personalityComponent: ecs.personalityComponent(args),
            mapSpawnComponent: ecs.builtSourceMapSpawnComponent(args),
            junctionComponent: ecs.junctionComponent(args),
            playerMadeComponent: ecs.fixedPlayerMadeComponent(args)
        };
    },
    cheer: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.cheer)));
        return ecs.currency(args);
    },
    flipMature: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flipMature)));
        return ecs.pairTransform(args);
    },
    toughButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.toughButton)));
        return ecs.towerButton(args);
    },
    generousTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.generousTower)));
        return ecs.tower(args);
    },
    damageIndicator: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.damageIndicator)));
        return {
            healthComponent: ecs.singleHealthComponent(args),
            timedDeathComponent: ecs.timedDeathComponent(args),
            rendererComponents: [ecs.damageIndicatorRenderComponent(args)]
        };
    },
    doUsefulGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.doUsefulGoal)));
        return ecs.worldGoal(args);
    },
    builtSourceMapSpawnComponent: function(args){
        args["mapSpawnKey"] = (args["mapSpawnKey"] === undefined) ? args.key + '_ext' : args["mapSpawnKey"];
        return {
            spawnDone: false,
            mapPostSpawn: trueFunction,
            tickos: 15,
            mapSpawnPos: builtSourceMapSpawnPos,
            mapShouldSpawn: builtSourceMapShouldSpawn,
            impulseTicks: 15,
            mapSpawn: mapSpawn,
            tendPosition: (args["tendPosition"] === undefined) ? false : args["tendPosition"],
            mapSpawnKey: args['mapSpawnKey']
        };
    },
    memoryGoalButton: function(args){
        args["managerKey"] = args.sourceKey;
        args["subPanel"] = (args["subPanel"] === undefined) ? "Goals" : args["subPanel"];
        return {
            uiActionComponent: ecs.buttonUiActionComponent(args),
            buttonControlComponent: ecs.goalButtonControlComponent(args),
            createExecutables: [ecs.killIfFlagExec(args), ecs.markTraitNew(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    spendTimeWarmGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeWarmGoalConstruction)));
        return ecs.construction(args);
    },
    calmPartnerGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmPartnerGoalConstruction)));
        return ecs.construction(args);
    },
    source: function(args){
        args["touchable"] = true;
        return {
            junctionComponent: ecs.junctionComponent(args),
            rendererComponents: [ecs.sourceRenderComponent(args)],
            clickComponent: ecs.fullMenuClickComponent(args),
            uniqueComponent: ecs.assertUniqueComponent(args),
            focusPathStopComponent: ecs.sourceFocusPathStopComponent(args),
            focusTickerComponent: ecs.focusTickerComponent(args),
            focusMakingComponent: (args.focusCount) ? ecs.focusMakingComponent(args) : undefined,
            interactionComponent: ecs.interactionComponent(args),
            healthComponent: ecs.healthComponent(args),
            creepAcceptComponent: ecs.creepAcceptComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.fixedPlayerMadeComponent(args)
        };
    },
    fixedPlayerMadeComponent: function(args){
        return {
            playerKillable: false,
            canExpandInto: false
        };
    },
    flashback_complimentSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_complimentSmall)));
        return ecs.emotionResource(args);
    },
    complimentSwarm: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentSwarm)));
        return ecs.instantEmotionResource(args);
    },
    clickText: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.clickText)));
        return {
            rendererComponents: [ecs.clickTextRenderComponent(args)],
            timedDeathComponent: ecs.timedDeathComponent(args),
            clickComponent: ecs.clickKillComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args)
        };
    },
    memory_aloneFlatYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_aloneFlatYou)));
        return ecs.memory(args);
    },
    whatsNewMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.whatsNewMenu)));
        return ecs.goalCompleteMenu(args);
    },
    criticismSwarm: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismSwarm)));
        return ecs.instantEmotionResource(args);
    },
    randomReplaceMarker: function(args){
        return {
            goodEntities: (args["goodEntities"] === undefined) ? [] : args["goodEntities"],
            badEntities: (args["badEntities"] === undefined) ? [] : args["badEntities"],
            addReplaceMarker: (args["addReplaceMarker"] === undefined) ? true : args["addReplaceMarker"],
            getReplaceKeys: randomReplaceGetReplaceKeys
        };
    },
    connectSource: function(args){
        return {
            replaceMarker: ecs.connectSourceReplaceMarker(args)
        };
    },
    setTrainColor: function(args){
        return {
            execute: setTrainColorExec
        };
    },
    memory_sadAttack: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_sadAttack)));
        return ecs.memory(args);
    },
    spendTimeResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeResult)));
        return ecs.randomReplace(args);
    },
    memoryIsaacEntityComponent: function(args){
        return {
            endLifecycle: endLifecycle,
            startLifecycle: memoryStartLifecycle,
            makeLifecycleEntities: makeLifecycleEntities,
            entitiesMade: []
        };
    },
    hardWorkGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hardWorkGoalConstruction)));
        return ecs.construction(args);
    },
    learnHimButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.learnHimButton)));
        return ecs.goalButton(args);
    },
    memoryGoalCompleteExec: function(args){
        return {
            execute: memoryGoalCompleteExec,
            bonusTime: (args["bonusTime"] === undefined) ? 30 : args["bonusTime"],
            flareMemory: (args["flareMemory"] === undefined) ? false : args["flareMemory"],
            killMemory: (args["killMemory"] === undefined) ? false : args["killMemory"]
        };
    },
    resourceFocusTickResponseComponent: function(args){
        return {
            firstTick: true,
            emotionTags: (args["emotionTags"] === undefined) ? undefined : args["emotionTags"],
            destination: (args["destination"] === undefined) ? undefined : args["destination"],
            focusTick: resourceFocusTick,
            focusTickHook: trueFunction
        };
    },
    selfishness: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfishness)));
        return ecs.currency(args);
    },
    oldLife: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldLife)));
        return ecs.emotionSource(args);
    },
    flashback_insecureSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_insecureSmall)));
        return ecs.emotionResource(args);
    },
    relationshipPathHisWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.relationshipPathHisWork)));
        return ecs.pathMaker(args);
    },
    difficultySetting: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.difficultySetting)));
        return {
            identityComponent: ecs.identityComponent(args),
            difficultySettingComponent: ecs.difficultySettingComponent(args)
        };
    },
    opinionConditionalMake: function(args){
        return {
            healthComponent: ecs.healthComponent(args),
            createExecutables: [ecs.opinionConditionalExec(args), ecs.killEntity(args)]
        };
    },
    soberDownMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.soberDownMenu)));
        return ecs.goalCompleteMenu(args);
    },
    clickTextRenderComponent: function(args){
        return {
            priority: 9,
            renderState: "default",
            render: clickTextRender
        };
    },
    guiltMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.guiltMenu)));
        return ecs.goalCompleteMenu(args);
    },
    needBusyAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needBusyAction)));
        return ecs.currencyAction(args);
    },
    timedFocusHolder: function(args){
        return {
            interactionComponent: ecs.interactionComponent(args),
            focusCostComponent: ecs.focusCostComponent(args),
            identityComponent: ecs.identityComponent(args),
            timedDeathComponent: ecs.timedDeathComponent(args)
        };
    },
    flashback_insecureSmallConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_insecureSmallConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    uniqueComponent: function(args){
        return {
            uniqueDuplicateEvent: falseFunction
        };
    },
    restLife: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.restLife)));
        return ecs.trait(args);
    },
    forceOpennessGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.forceOpennessGoal)));
        return ecs.worldGoal(args);
    },
    killEntityComponent: function(args){
        return {
            entitiesToKill: (args["entitiesToKill"] === undefined) ? [] : args["entitiesToKill"],
            execute: executeKillEntities
        };
    },
    feelUselessGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.feelUselessGoalConstruction)));
        return ecs.construction(args);
    },
    selfExtensionRender: function(args){
        return {
            priority: 6,
            renderState: "default",
            render: selfExtensionRender
        };
    },
    interruptionSwarm: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.interruptionSwarm)));
        return ecs.instantEmotionResource(args);
    },
    getOverBadWorkButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getOverBadWorkButton)));
        return ecs.goalButton(args);
    },
    goodWorkDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goodWorkDeposit)));
        return ecs.deposit(args);
    },
    entityLifecycleComponent: function(args){
        if (args.startLifecycle === undefined){ throw "ECS fail " + args.key + " missing startLifecycle"; }
        return {
            endLifecycle: endLifecycle,
            startLifecycle: args['startLifecycle'],
            makeLifecycleEntities: makeLifecycleEntities,
            entitiesMade: []
        };
    },
    stateTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.stateTowerConstruction)));
        return ecs.construction(args);
    },
    switchValueDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.switchValueDeposit)));
        return ecs.switch(args);
    },
    fascinateGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.fascinateGoal)));
        return ecs.worldGoal(args);
    },
    takeOutFrustrationMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeOutFrustrationMenu)));
        return ecs.goalCompleteMenu(args);
    },
    dailyHelpInfoPanel: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.dailyHelpInfoPanel)));
        return ecs.helpInfoPanel(args);
    },
    casualMedHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.casualMedHim)));
        return ecs.instantEmotionResource(args);
    },
    pathStopRenderComponent: function(args){
        if (args.activeImage === undefined){ throw "ECS fail " + args.key + " missing activeImage"; }
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            priority: 7,
            outlineImage: false,
            render: pathStopRender,
            activeImage: args['activeImage'],
            wobble: 0,
            image: args['image'],
            blinkingOutlineTime: 0,
            timeDrawn: 0,
            outlineTime: 0,
            blinkingOutlineImage: false,
            renderTime: 0.1,
            getWobble: getWobble,
            renderState: "default",
            renderTrainIcon: renderTrainIcon,
            isActive: false
        };
    },
    startConverseButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startConverseButton)));
        return ecs.goalButton(args);
    },
    gameStageDayResponseComponent: function(args){
        return {
            dayEnd: gameStageDayEnd,
            dayStart: (args["dayStart"] === undefined) ? undefined : args["dayStart"],
            daysLeft: 2,
            dayChange: (args["dayChange"] === undefined) ? undefined : args["dayChange"]
        };
    },
    himself: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.himself)));
        return ecs.source(args);
    },
    swallowOpinionCreate: function(args){
        return {
            execute: swallowOpinionCreate,
            swallowExceptions: (args["swallowExceptions"] === undefined) ? [] : args["swallowExceptions"]
        };
    },
    feedCrisisMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.feedCrisisMenu)));
        return ecs.goalCompleteMenu(args);
    },
    truthTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.truthTowerConstruction)));
        return ecs.construction(args);
    },
    particleEffect: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            lifeSentinelComponent: ecs.sourceLifeSentinelComponent(args),
            rendererComponents: [ecs.particleEffectRenderComponent(args)]
        };
    },
    insecurityPathFun: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecurityPathFun)));
        return ecs.pathMaker(args);
    },
    emotionSource: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            emotionSourceComponent: ecs.emotionSourceComponent(args),
            createExecutables: [ecs.emotionSourceCreateExec(args), ecs.killEntity(args)]
        };
    },
    timedCreateEntities: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            timedDeathComponent: ecs.timedDeathComponent(args)
        };
    },
    tutorialUnpause: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            tutorialTextComponent: ecs.tutorialUnpauseTextComponent(args),
            rendererComponents: [ecs.tutorialUnpauseRenderComponent(args)]
        };
    },
    aloneFlatYouMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.aloneFlatYouMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    flashback_guiltMedConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_guiltMedConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    selfDamageEffect: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            lifeSentinelComponent: ecs.sourceLifeSentinelComponent(args),
            rendererComponents: [ecs.selfDamageEffectRenderComponent(args)]
        };
    },
    absolutePositionComponent: function(args){
        return {
            getAbsPosRect: getAbsPosRect,
            draggable: (args["draggable"] === undefined) ? true : args["draggable"],
            isDragging: false,
            setAbsPosFromRect: setAbsPosFromRect,
            y: (args["y"] === undefined) ? 0 : args["y"],
            x: (args["x"] === undefined) ? 0 : args["x"],
            size: (args["size"] === undefined) ? [0, 0] : args["size"]
        };
    },
    disableMemories: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.disableMemories)));
        args["name"] = "You're just too overwhelmed to feel this right now.";
        return {
            disableTraitComponent: ecs.disableMemoriesComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            identityComponent: ecs.identityComponent(args),
            tickComponent: ecs.disableMemoriesTickComponent(args),
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined
        };
    },
    tryNewGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryNewGoal)));
        return ecs.worldGoal(args);
    },
    goodWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goodWork)));
        return ecs.currency(args);
    },
    explainFindUsefulFail: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.explainFindUsefulFail)));
        return ecs.menuModifier(args);
    },
    newRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.newRelationship)));
        return ecs.trait(args);
    },
    oddity: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oddity)));
        return ecs.currency(args);
    },
    flashback_resentMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_resentMed)));
        return ecs.emotionResource(args);
    },
    groupPanel: function(args){
        args["y"] = 5;
        args["x"] = (width - 800) / 2;
        args["size"] = [800, 300];
        return {
            panelComponent: ecs.panelComponent(args),
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            identityComponent: ecs.identityComponent(args),
            uniqueComponent: ecs.uniqueComponent(args)
        };
    },
    placedTowerReplaceMarker: function(args){
        if (args.tower === undefined){ throw "ECS fail " + args.key + " missing tower"; }
        if (args.x === undefined){ throw "ECS fail " + args.key + " missing x"; }
        if (args.y === undefined){ throw "ECS fail " + args.key + " missing y"; }
        if (args.sourceTrait === undefined){ throw "ECS fail " + args.key + " missing sourceTrait"; }
        return {
            y: args['y'],
            x: args['x'],
            tower: args['tower'],
            sourceTrait: args['sourceTrait'],
            getReplaceKeys: placedTowerGetReplaceKeys
        };
    },
    overcomeHurtMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.overcomeHurtMenu)));
        return ecs.goalCompleteMenu(args);
    },
    supportButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportButton)));
        return ecs.memoryTowerButton(args);
    },
    currencyRequest: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            positionComponent: ecs.positionComponent(args),
            requestComponent: ecs.requestComponent(args)
        };
    },
    instantEmotionOther: function(args){
        args["touchable"] = true;
        args["destination"] = args.source ? (args.source.interactionComponent.canInteractSelf() ? 'himself' : PARAMETERS.self) : null;
        args["canExpandInto"] = false;
        args["playerKillable"] = false;
        return {
            interactionComponent: ecs.interactionComponent(args),
            junctionComponent: ecs.junctionComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args)],
            focusTickResponseComponent: ecs.resourceFocusTickResponseComponent(args),
            managedComponent: ecs.managedComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)].concat([ecs.emotionResourceDifficultyExec(args)]),
            focusPathStopComponent: ecs.resourceFocusPathStopComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            tickComponent: ecs.instantEmotionResourceTickComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            resourceComponent: ecs.resourceComponent(args),
            killExecutables: [ecs.killResourceCurrencies(args)],
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            loseControlExec: ecs.killEntity(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    swallowOpinion: function(args){
        args["isaacEntities"] = generateOpinionIsaacs(args);
        return {
            isaacEntityComponent: ecs.isaacEntityComponent(args),
            opinionComponent: ecs.opinionComponent(args),
            focusTickResponseComponent: (args.aliveEntities) ? ecs.aliveMakeComponent(args) : undefined,
            personHeldComponent: ecs.personHeldComponent(args),
            swallowOpinionComponent: ecs.swallowOpinionComponent(args),
            createExecutables: [ecs.swallowOpinionCreate(args), ecs.killPersonGoals(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            killExecutables: [ecs.swallowOpinionKill(args)],
            tickComponent: ecs.opinionTickComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            focusMakingComponent: (args.focusCount) ? ecs.focusMakingComponent(args) : undefined,
            identityComponent: ecs.identityComponent(args)
        };
    },
    switchReplaceMarker: function(args){
        if (args.entitiesToMake === undefined){ throw "ECS fail " + args.key + " missing entitiesToMake"; }
        return {
            entitiesToMake: args['entitiesToMake'],
            getReplaceKeys: switchGetReplaceKeys
        };
    },
    complimentTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentTower)));
        return ecs.tower(args);
    },
    upgradeButton: function(args){
        args["subPanel"] = (args["subPanel"] === undefined) ? "Upgrades" : args["subPanel"];
        args["multiTrait"] = (args["multiTrait"] === undefined) ? false : args["multiTrait"];
        return {
            interactionComponent: ecs.interactionComponent(args),
            uiActionComponent: ecs.buttonUiActionComponent(args),
            buttonControlComponent: ecs.upgradeControlComponent(args),
            createExecutables: [ecs.markTraitNew(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            uniqueComponent: (args.timeToDeath === undefined && !args.multiTrait) ? ecs.uniqueComponent(args) : undefined,
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            killExecutables: [ecs.killTowerButtonExec(args)],
            identityComponent: ecs.identityComponent(args)
        };
    },
    tickModifyComponent: function(args){
        if (args.tickFactor === undefined){ throw "ECS fail " + args.key + " missing tickFactor"; }
        if (args.towerId === undefined){ throw "ECS fail " + args.key + " missing towerId"; }
        if (args.distractFactor === undefined){ throw "ECS fail " + args.key + " missing distractFactor"; }
        return {
            tickFactor: args['tickFactor'],
            distractFactor: args['distractFactor'],
            tickModifyInteraction: (args["tickModifyInteraction"] === undefined) ? trueFunction : args["tickModifyInteraction"],
            towerId: args['towerId']
        };
    },
    searchWorthGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.searchWorthGoalConstruction)));
        return ecs.construction(args);
    },
    clickComponent: function(args){
        if (args.onClick === undefined){ throw "ECS fail " + args.key + " missing onClick"; }
        return {
            onClick: args['onClick']
        };
    },
    flirtation: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtation)));
        return ecs.currency(args);
    },
    setDefineRoleDone: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.setDefineRoleDone)));
        return ecs.setFlag(args);
    },
    hisGoodWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisGoodWork)));
        return ecs.trait(args);
    },
    currencyDayResponseComponent: function(args){
        return {
            dayEnd: currencyDayEnd,
            dayStart: (args["dayStart"] === undefined) ? undefined : args["dayStart"],
            dayChange: (args["dayChange"] === undefined) ? undefined : args["dayChange"]
        };
    },
    complimentFlatYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentFlatYou)));
        return ecs.emotionSource(args);
    },
    thankGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.thankGoal)));
        return ecs.worldGoal(args);
    },
    complimentAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentAction)));
        return ecs.currencyAction(args);
    },
    traitParticleEffectLifeSentinelComponent: function(args){
        if (args.managerKey === undefined){ throw "ECS fail " + args.key + " missing managerKey"; }
        return {
            managerKey: args['managerKey'],
            checkAlive: checkTraitParticleEffectAlive
        };
    },
    supportCrisisButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportCrisisButton)));
        return ecs.goalButton(args);
    },
    upgradeControlComponent: function(args){
        if (args.baseKeys === undefined){ throw "ECS fail " + args.key + " missing baseKeys"; }
        if (args.entityKey === undefined){ throw "ECS fail " + args.key + " missing entityKey"; }
        if (args.constructionKey === undefined){ throw "ECS fail " + args.key + " missing constructionKey"; }
        return {
            aiVal: (args["aiVal"] === undefined) ? 0 : args["aiVal"],
            constructionKey: args['constructionKey'],
            checkMakePos: checkUpgradePos,
            baseKeys: args['baseKeys'],
            currenciesMade: (args["currenciesMade"] === undefined) ? [] : args["currenciesMade"],
            isNew: true,
            canMakeEntity: canMakeUpgrade,
            entityKey: args['entityKey'],
            wrappedFunction: undefined,
            managerKey: (args["managerKey"] === undefined) ? args.sourceKey : args["managerKey"],
            makeEntity: upgradeTower,
            getAiVal: controlComponentGetAiVal,
            getWrappedFunction: getWrappedFunction,
            baseUpgradeTowerForPos: baseUpgradeTowerForPos
        };
    },
    flirtationMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtationMineConstruction)));
        return ecs.construction(args);
    },
    resentYouMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.resentYouMine)));
        return ecs.emotionResource(args);
    },
    getFeedbackGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getFeedbackGoal)));
        return ecs.worldGoal(args);
    },
    youInfo: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.youInfo)));
        return ecs.currency(args);
    },
    makeIfMissingExec: function(args){
        if (args.entitiesToMake === undefined){ throw "ECS fail " + args.key + " missing entitiesToMake"; }
        if (args.missingKey === undefined){ throw "ECS fail " + args.key + " missing missingKey"; }
        if (args.source === undefined){ throw "ECS fail " + args.key + " missing source"; }
        return {
            source: args['source'],
            execute: makeIfMissingExec,
            entitiesToMake: args['entitiesToMake'],
            missingKey: args['missingKey']
        };
    },
    goodPathYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goodPathYou)));
        return ecs.pathMaker(args);
    },
    selfEsteem: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfEsteem)));
        return ecs.currency(args);
    },
    tryNewResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryNewResult)));
        return ecs.randomReplace(args);
    },
    viceTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.viceTowerConstruction)));
        return ecs.construction(args);
    },
    aloneMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.aloneMed)));
        return ecs.creep(args);
    },
    insecurityToSearchingWorth: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecurityToSearchingWorth)));
        return ecs.transformExec(args);
    },
    valueDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.valueDeposit)));
        return ecs.deposit(args);
    },
    accuseSelfishGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.accuseSelfishGoalConstruction)));
        return ecs.construction(args);
    },
    creepDeathExec: function(args){
        return {
            execute: creepDeathExec,
            creepDeathKey: "creepDeath"
        };
    },
    clickKillComponent: function(args){
        return {
            onClick: clickKill
        };
    },
    planSomethingFunMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.planSomethingFunMenu)));
        return ecs.goalCompleteMenu(args);
    },
    goalCompleteMenuCreateExec: function(args){
        return {
            source: (args["source"] === undefined) ? undefined : args["source"],
            execute: goalCompleteMenuCreateExec
        };
    },
    quietTimeGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.quietTimeGoal)));
        return ecs.worldGoal(args);
    },
    transformTrait: function(args){
        if (args.sourceTrait === undefined){ throw "ECS fail " + args.key + " missing sourceTrait"; }
        if (args.newTrait === undefined){ throw "ECS fail " + args.key + " missing newTrait"; }
        return {
            retainHealth: (args["retainHealth"] === undefined) ? true : args["retainHealth"],
            execute: transformTrait,
            sourceTrait: args['sourceTrait'],
            newTrait: args['newTrait']
        };
    },
    crueltyButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.crueltyButton)));
        return ecs.towerButton(args);
    },
    makeCurrencyRequest: function(args){
        if (args.currencyRequested === undefined){ throw "ECS fail " + args.key + " missing currencyRequested"; }
        return {
            execute: makeCurrencyRequest,
            requestKey: PARAMETERS.currencyRequest,
            currencyRequested: args['currencyRequested']
        };
    },
    overcomeHurtGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.overcomeHurtGoalConstruction)));
        return ecs.construction(args);
    },
    allGoalPanel: function(args){
        args["y"] = 5;
        args["x"] = (width - 800) / 2;
        args["key"] = PARAMETERS.allGoalPanel;
        args["size"] = [800, 300];
        return {
            rendererComponents: [ecs.allGoalPanelRenderComponent(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            panelComponent: ecs.panelComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    complimentSwarmYouMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentSwarmYouMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    controlPanel: function(args){
        return {
            panelTrackComponent: ecs.panelTrackComponent(args),
            keyPressComponent: ecs.controlPanelKeyPressComponent(args)
        };
    },
    viceFlatHim: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.viceFlatHim)));
        return ecs.instantEmotionResource(args);
    },
    panelUiClickComponent: function(args){
        return {
            uiClick: panelUiClick
        };
    },
    fearTickModifier: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.fearTickModifier)));
        return {
            healthComponent: ecs.singleHealthComponent(args),
            tickModifyComponent: ecs.fearTickModifyComponent(args),
            rendererComponents: [ecs.towerTickModifierRenderComponent(args)],
            dayResponseComponent: ecs.killDayEndComponent(args),
            timedDeathComponent: ecs.timedDeathComponent(args)
        };
    },
    personGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.personGoal)));
        args["particleKey"] = PARAMETERS.newParticle;
        args["description"] = (args.description && args.description[args.personHeld]) ? args.description[args.personHeld] : args.description;
        args["touchable"] = true;
        args["playerKillable"] = !!(args.constructed);
        args["startEntityKey"] = args.personHeld;
        args["canExpandInto"] = false;
        args["currencyRequested"] = derivePersonGoalCurrencies(args.currencyRequested, args.personHeld);
        args["killOnTransform"] = (args["killOnTransform"] === undefined) ? true : args["killOnTransform"];
        if (args.personHeld === undefined){ throw "ECS fail " + args.key + " missing personHeld"; }
        return {
            uiActionComponent: ecs.buildingUiActionComponent(args),
            goalTrackComponent: ecs.personGoalTrackComponent(args),
            createExecutables: [ecs.checkManagedComponentExec(args), (args.randomPosition) ? ecs.randomOpenPositionExec(args) : undefined, ecs.makeExtraPathsExec(args), ecs.chkForPlayerInterrupt(args), ecs.buildingConnectExec(args), (args.timeToDeath) ? ecs.timedDifficultyModifyExec(args) : undefined],
            timedDeathComponent: (args.timeToDeath) ? ecs.worldGoalTimedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            rendererComponents: [ecs.worldGoalRenderComponent(args), ecs.progressRenderComponent(args), ecs.timedDeathRenderComponent(args)],
            focusTickResponseComponent: (args.aliveEntities) ? ecs.aliveMakeComponent(args) : undefined,
            managedComponent: (args.sourceTrait) ? ecs.managedComponent(args) : undefined,
            flipComponent: (args.flipEntity) ? ecs.flipComponent(args) : undefined,
            personHeldComponent: ecs.personHeldComponent(args),
            worldGoalComponent: ecs.worldGoalComponent(args),
            focusPathStopComponent: ecs.worldGoalFocusPathStopComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            positionComponent: ecs.positionComponent(args),
            notificationComponents: [ecs.worldGoalNotificationComponent(args)],
            junctionComponent: ecs.junctionComponent(args),
            pauseComponent: ecs.pauseComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    flashback_viceMedConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_viceMedConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    hisGoodWorkToRestless: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisGoodWorkToRestless)));
        return ecs.transformExec(args);
    },
    controlComponent: function(args){
        if (args.makeEntity === undefined){ throw "ECS fail " + args.key + " missing makeEntity"; }
        if (args.canMakeEntity === undefined){ throw "ECS fail " + args.key + " missing canMakeEntity"; }
        if (args.checkMakePos === undefined){ throw "ECS fail " + args.key + " missing checkMakePos"; }
        return {
            aiVal: (args["aiVal"] === undefined) ? 0 : args["aiVal"],
            checkMakePos: args['checkMakePos'],
            isNew: true,
            canMakeEntity: args['canMakeEntity'],
            currenciesMade: (args["currenciesMade"] === undefined) ? [] : args["currenciesMade"],
            wrappedFunction: undefined,
            managerKey: (args["managerKey"] === undefined) ? args.sourceKey : args["managerKey"],
            makeEntity: args['makeEntity'],
            getAiVal: controlComponentGetAiVal,
            getWrappedFunction: getWrappedFunction
        };
    },
    calmnessButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmnessButton)));
        return ecs.towerButton(args);
    },
    askHelpGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askHelpGoalConstruction)));
        return ecs.construction(args);
    },
    impulseFocusStop: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            focusPathStopComponent: ecs.impulseFocusPathStopComponent(args),
            positionComponent: ecs.positionComponent(args)
        };
    },
    trainPath: function(args){
        return {
            rendererComponents: [ecs.trainPathTowerActiveRender(args), ecs.trainPathSecondRender(args), ecs.trainPathCircRenderComponent(args)],
            trainPathComponent: ecs.trainPathComponent(args),
            menuCloseComponent: ecs.trainPathMenuCloseComponent(args),
            createExecutables: [ecs.setTrainColor(args)],
            killExecutables: [ecs.blinkTrainStops(args)],
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            focusCostComponent: ecs.focusCostComponent(args)
        };
    },
    bulletRenderComponent: function(args){
        if (args.bulletSourcePos === undefined){ throw "ECS fail " + args.key + " missing bulletSourcePos"; }
        if (args.bulletEndPos === undefined){ throw "ECS fail " + args.key + " missing bulletEndPos"; }
        if (args.damage === undefined){ throw "ECS fail " + args.key + " missing damage"; }
        if (args.bonus === undefined){ throw "ECS fail " + args.key + " missing bonus"; }
        return {
            render: bulletRender,
            bonus: args['bonus'],
            bulletSourcePos: args['bulletSourcePos'],
            damage: args['damage'],
            priority: 9,
            renderState: "default",
            bulletEndPos: args['bulletEndPos']
        };
    },
    insecurity_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecurity_ext)));
        return ecs.sourceExtension(args);
    },
    socialButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialButton)));
        return ecs.towerButton(args);
    },
    timeForceExec: function(args){
        return {
            execute: timeForceExec
        };
    },
    hisWorkToHisGoodWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisWorkToHisGoodWork)));
        return ecs.transformExec(args);
    },
    clearNewRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.clearNewRelationship)));
        return ecs.clearTrait(args);
    },
    openUpDone: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.openUpDone)));
        return ecs.endGoal(args);
    },
    addPersonAndOpinion: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.addPersonAndOpinionExec(args)]
        };
    },
    goalButton: function(args){
        args["subPanel"] = (args["subPanel"] === undefined) ? "Goals" : args["subPanel"];
        return {
            uiActionComponent: ecs.buttonUiActionComponent(args),
            buttonControlComponent: ecs.goalButtonControlComponent(args),
            createExecutables: [ecs.killIfFlagExec(args), ecs.markTraitNew(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    makeComplimentFlatGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeComplimentFlatGoal)));
        return ecs.worldGoal(args);
    },
    searchWorthMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.searchWorthMenu)));
        return ecs.goalCompleteMenu(args);
    },
    beSupportedBranch: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.beSupportedBranch)));
        return ecs.flagBranch(args);
    },
    towerTickModifierRenderComponent: function(args){
        if (args.key === undefined){ throw "ECS fail " + args.key + " missing key"; }
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            render: towerTickModifierRender,
            image: args['image'],
            priority: 11,
            key: args['key'],
            getTowerForTickModifierRender: getTowerForTickModifierRender,
            renderState: "default"
        };
    },
    whatsNewGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.whatsNewGoal)));
        return ecs.worldGoal(args);
    },
    strengthMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.strengthMine)));
        return ecs.resource(args);
    },
    memory_casualSwarmYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_casualSwarmYou)));
        return ecs.memory(args);
    },
    opinion: function(args){
        args["isaacEntities"] = generateOpinionIsaacs(args);
        return {
            isaacEntityComponent: ecs.isaacEntityComponent(args),
            opinionComponent: ecs.opinionComponent(args),
            focusTickResponseComponent: (args.aliveEntities) ? ecs.aliveMakeComponent(args) : undefined,
            personHeldComponent: ecs.personHeldComponent(args),
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            focusMakingComponent: (args.focusCount) ? ecs.focusMakingComponent(args) : undefined,
            tickComponent: ecs.opinionTickComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    startConverseGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startConverseGoalConstruction)));
        return ecs.construction(args);
    },
    criticismButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismButton)));
        return ecs.towerButton(args);
    },
    toughTowerPlaced: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.toughTowerPlaced)));
        return ecs.placedTower(args);
    },
    toastClickComponent: function(args){
        if (args.panelKey === undefined){ throw "ECS fail " + args.key + " missing panelKey"; }
        return {
            onClick: toastClick,
            panelKey: args['panelKey']
        };
    },
    talkInterestingMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkInterestingMenu)));
        return ecs.goalCompleteMenu(args);
    },
    uiDataComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            subPanel: (args["subPanel"] === undefined) ? undefined : args["subPanel"],
            image: args['image'],
            drawImage: uiDataDrawImage,
            lastPath: undefined
        };
    },
    resentMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.resentMed)));
        return ecs.creep(args);
    },
    socialCleverMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialCleverMineButton)));
        return ecs.resourceButton(args);
    },
    workWin: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.workWin)));
        return ecs.currency(args);
    },
    flirtHimButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtHimButton)));
        return ecs.goalButton(args);
    },
    stateButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.stateButton)));
        return ecs.towerButton(args);
    },
    goalCompleteExec: function(args){
        return {
            execute: goalCompleteExec
        };
    },
    deriveWorkTopicButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.deriveWorkTopicButton)));
        return ecs.goalButton(args);
    },
    shareJoyTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.shareJoyTowerConstruction)));
        return ecs.construction(args);
    },
    friendMeditateButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.friendMeditateButton)));
        return ecs.towerButton(args);
    },
    opennessButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.opennessButton)));
        return ecs.towerButton(args);
    },
    oldEmo: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldEmo)));
        return ecs.splitReplace(args);
    },
    clever: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.clever)));
        return ecs.trait(args);
    },
    trait: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.trait)));
        args["touchable"] = true;
        args["health"] = (args["health"] === undefined) ? 2000 : args["health"];
        args["panelKey"] = (args["panelKey"] === undefined) ? PARAMETERS.traitPanel : args["panelKey"];
        return {
            killExecutables: [ecs.killExtensions(args)],
            isaacEntityComponent: ecs.isaacEntityComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            rendererComponents: [ecs.builtSourceRendererComponent(args)],
            uiActionComponent: ecs.buildingUiActionComponent(args),
            focusTickResponseComponent: (args.aliveEntities) ? ecs.focusTickAliveMakerComponent(args) : undefined,
            mapSpawnComponent: ecs.builtSourceMapSpawnComponent(args),
            experienceComponent: ecs.experienceComponent(args),
            personHeldComponent: (args.personHeld) ? ecs.personHeldComponent(args) : undefined,
            createExecutables: [ecs.builtSourceCreateExec(args), ecs.makeExtraPathsExec(args)],
            junctionComponent: ecs.junctionComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            entityManagerComponent: ecs.entityManagerComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.healthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            menuCloseComponent: ecs.traitMenuCloseComponent(args),
            playerMadeComponent: ecs.fixedPlayerMadeComponent(args)
        };
    },
    train: function(args){
        return {
            rendererComponents: [ecs.trainRenderComponent(args)],
            trainComponent: ecs.trainComponent(args),
            trainVelocityComponent: ecs.trainVelocityComponent(args),
            createExecutables: [ecs.trainCreateExec(args)],
            killExecutables: [ecs.trainKillExec(args)],
            healthComponent: ecs.singleHealthComponent(args),
            positionComponent: ecs.positionComponent(args)
        };
    },
    trySomethingGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.trySomethingGoalConstruction)));
        return ecs.construction(args);
    },
    chapterPanelRenderComponent: function(args){
        return {
            insetColor: "#000000",
            canShowGoal: chapterPanelCanShowGoal,
            tickImage: "tick",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "uiBack",
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            priority: 18,
            render: outPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            showGoal: chapterPanelShowGoal,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            goalOpenFunctions: {},
            specificRender: chapterPanelRender,
            drawHelpButton: drawHelpButton
        };
    },
    subconsciousRequestComponent: function(args){
        return {
            needsWorker: trueFunction,
            calculateWorkerTicks: calculateWorkerTicks,
            workerRequested: args.sourceTrait ? (args.sourceTrait + '_subconscious') : PARAMETERS.subconsciousWorkerKey,
            workersActive: [],
            workerCount: 1,
            subconsciousRequest: true,
            workerLife: 20
        };
    },
    cleverPathRestless: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.cleverPathRestless)));
        return ecs.pathMaker(args);
    },
    findHelpButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findHelpButton)));
        return ecs.goalButton(args);
    },
    indulgeViceGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.indulgeViceGoalConstruction)));
        return ecs.construction(args);
    },
    flashback_resentMedConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_resentMedConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    reinforceStupidGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reinforceStupidGoal)));
        return ecs.worldGoal(args);
    },
    overcomeHurtGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.overcomeHurtGoal)));
        return ecs.worldGoal(args);
    },
    slowWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.slowWork)));
        return ecs.currency(args);
    },
    endGoalExec: function(args){
        if (args.flag === undefined){ throw "ECS fail " + args.key + " missing flag"; }
        if (args.buttonKey === undefined){ throw "ECS fail " + args.key + " missing buttonKey"; }
        return {
            buttonKey: args['buttonKey'],
            execute: endGoalExecute,
            flag: args['flag']
        };
    },
    completeWorkButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.completeWorkButton)));
        return ecs.goalButton(args);
    },
    startRelationYouGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startRelationYouGoal)));
        return ecs.worldGoal(args);
    },
    allTrainPanel: function(args){
        args["y"] = 5;
        args["x"] = (width - 800) / 2;
        args["key"] = PARAMETERS.allTrainPanel;
        args["size"] = [500, 625];
        return {
            rendererComponents: [ecs.allTrainPanelRenderComponent(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            panelComponent: ecs.panelComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    explainSpendTimeFail: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.explainSpendTimeFail)));
        return ecs.menuModifier(args);
    },
    talkAboutYouButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkAboutYouButton)));
        return ecs.goalButton(args);
    },
    killTraitExec: function(args){
        if (args.traitToKill === undefined){ throw "ECS fail " + args.key + " missing traitToKill"; }
        return {
            traitToKill: args['traitToKill'],
            execute: killTraitExec
        };
    },
    fishComplimentsGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.fishComplimentsGoal)));
        return ecs.worldGoal(args);
    },
    demolishPathButton: function(args){
        return {
            rendererComponents: [ecs.demolishPathRenderComponent(args)]
        };
    },
    conditionalMakeReplaceMarker: function(args){
        if (args.entitiesToMake === undefined){ throw "ECS fail " + args.key + " missing entitiesToMake"; }
        if (args.stopEntities === undefined){ throw "ECS fail " + args.key + " missing stopEntities"; }
        return {
            entitiesToMake: args['entitiesToMake'],
            stopEntities: args['stopEntities'],
            getReplaceKeys: conditionalMakeGetReplaceKeys
        };
    },
    criticizeSelfGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticizeSelfGoal)));
        return ecs.worldGoal(args);
    },
    breakdownMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.breakdownMenu)));
        return ecs.goalCompleteMenu(args);
    },
    indulgeViceButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.indulgeViceButton)));
        return ecs.goalButton(args);
    },
    spendTimeCleverGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeCleverGoalConstruction)));
        return ecs.construction(args);
    },
    worthlessFeel: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worthlessFeel)));
        return ecs.emotionSource(args);
    },
    calmnessTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.calmnessTowerConstruction)));
        return ecs.construction(args);
    },
    worthlessFeelMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worthlessFeelMine)));
        return ecs.emotionResource(args);
    },
    needPainTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needPainTowerConstruction)));
        return ecs.memoryConstruction(args);
    },
    selfValueTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfValueTowerConstruction)));
        return ecs.construction(args);
    },
    killExtensions: function(args){
        return {
            execute: killExtensions
        };
    },
    obsessHimButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessHimButton)));
        return ecs.towerButton(args);
    },
    connectFriendsGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.connectFriendsGoalConstruction)));
        return ecs.construction(args);
    },
    notificationSerializeComponent: function(args){
        return {
            serialize: args['serialize'],
            postSerialize: notificationSerialize
        };
    },
    setYouRelation: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.setYouRelation)));
        return ecs.setFlag(args);
    },
    flashback_worthlessSmallConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_worthlessSmallConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    spendTimeGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeGoal)));
        return ecs.worldGoal(args);
    },
    junction: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            junctionComponent: ecs.junctionComponent(args),
            positionComponent: ecs.positionComponent(args)
        };
    },
    spell: function(args){
        return {
            identityComponent: ecs.identityComponent(args),
            rendererComponents: [ecs.spellRenderComponent(args)],
            spellComponent: ecs.spellComponent(args)
        };
    },
    strengthMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.strengthMineButton)));
        return ecs.resourceButton(args);
    },
    workerRequireComponent: function(args){
        if (args.workerRequired === undefined){ throw "ECS fail " + args.key + " missing workerRequired"; }
        return {
            workerRequired: args['workerRequired'],
            workingTicks: 0
        };
    },
    day: function(args){
        return {
            dayCounterComponent: ecs.dayCounterComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            killExecutables: [ecs.dayKillExec(args)]
        };
    },
    speakOfValueGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.speakOfValueGoal)));
        return ecs.worldGoal(args);
    },
    flashback_oldFailSmallConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_oldFailSmallConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    truth: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.truth)));
        return ecs.currency(args);
    },
    singleUseTrainPath: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.singleUseTrainPath)));
        return {
            rendererComponents: [ecs.trainPathTowerActiveRender(args), ecs.trainPathSecondRender(args), ecs.trainPathCircRenderComponent(args)],
            trainPathComponent: ecs.singleUseTrainPathComponent(args),
            menuCloseComponent: ecs.trainPathMenuCloseComponent(args),
            createExecutables: [ecs.setTrainColor(args)],
            killExecutables: [ecs.blinkTrainStops(args)],
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            focusCostComponent: ecs.focusCostComponent(args)
        };
    },
    truthTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.truthTower)));
        return ecs.tower(args);
    },
    complimentYouMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentYouMenu)));
        return ecs.goalCompleteMenu(args);
    },
    reinforceCriticismGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reinforceCriticismGoal)));
        return ecs.worldGoal(args);
    },
    makeGoalMenuExecutable: function(args){
        if (args.goalMenuKey === undefined){ throw "ECS fail " + args.key + " missing goalMenuKey"; }
        return {
            execute: makeGoalMenuExecute,
            goalMenuKey: args['goalMenuKey']
        };
    },
    makeOldFailSwarmGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeOldFailSwarmGoalConstruction)));
        return ecs.construction(args);
    },
    oldFailSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldFailSmall)));
        return ecs.creep(args);
    },
    tryNewButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryNewButton)));
        return ecs.goalButton(args);
    },
    defineHelpGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.defineHelpGoalConstruction)));
        return ecs.construction(args);
    },
    towerControlComponent: function(args){
        if (args.entityCost === undefined){ throw "ECS fail " + args.key + " missing entityCost"; }
        if (args.entityKey === undefined){ throw "ECS fail " + args.key + " missing entityKey"; }
        if (args.constructionKey === undefined){ throw "ECS fail " + args.key + " missing constructionKey"; }
        if (args.limitingKeys === undefined){ throw "ECS fail " + args.key + " missing limitingKeys"; }
        return {
            aiVal: (args["aiVal"] === undefined) ? 0 : args["aiVal"],
            constructionKey: args['constructionKey'],
            checkMakePos: checkTowerMakePos,
            isNew: true,
            currenciesMade: (args["currenciesMade"] === undefined) ? [] : args["currenciesMade"],
            canMakeEntity: canBuildTower,
            entityKey: args['entityKey'],
            limitingKeys: args['limitingKeys'],
            wrappedFunction: undefined,
            managerKey: (args["managerKey"] === undefined) ? args.sourceKey : args["managerKey"],
            makeEntity: buildTower,
            getAiVal: controlComponentGetAiVal,
            getWrappedFunction: getWrappedFunction,
            maxTowerCount: (args["maxTowerCount"] === undefined) ? 2 : args["maxTowerCount"],
            entityCost: args['entityCost']
        };
    },
    selfDistractionTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfDistractionTowerConstruction)));
        return ecs.construction(args);
    },
    allCurrencyRenderComponent: function(args){
        return {
            priority: 13,
            image: "currency",
            renderState: "default",
            render: allCurrencyRender
        };
    },
    callousnessTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.callousnessTowerConstruction)));
        return ecs.construction(args);
    },
    damamgeUpgradeCheckExec: function(args){
        if (args.towerKey === undefined){ throw "ECS fail " + args.key + " missing towerKey"; }
        if (args.flag === undefined){ throw "ECS fail " + args.key + " missing flag"; }
        return {
            entitiesToKill: (args["entitiesToKill"] === undefined) ? [] : args["entitiesToKill"],
            maxUpgradeCount: (args["maxUpgradeCount"] === undefined) ? 3 : args["maxUpgradeCount"],
            execute: damamgeUpgradeCheckExec,
            towerKey: args['towerKey'],
            flag: args['flag']
        };
    },
    switchThankGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.switchThankGoal)));
        return ecs.switch(args);
    },
    randomMenuComponent: function(args){
        if (args.goodCount === undefined){ throw "ECS fail " + args.key + " missing goodCount"; }
        if (args.badCount === undefined){ throw "ECS fail " + args.key + " missing badCount"; }
        if (args.goodResult === undefined){ throw "ECS fail " + args.key + " missing goodResult"; }
        return {
            goodResult: args['goodResult'],
            goodCount: args['goodCount'],
            badCount: args['badCount']
        };
    },
    killCurrency: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.killCurrencyExec(args), ecs.killEntity(args)]
        };
    },
    tempTrait: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tempTrait)));
        return ecs.trait(args);
    },
    tutorialText: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            tutorialTextComponent: ecs.tutorialTextComponent(args),
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            rendererComponents: [ecs.tutorialTextRenderComponent(args)]
        };
    },
    towerFocusPathStopComponent: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.towerFocusPathStopComponent)));
        return {
            interactWithTrain: towerInteractWithTrain,
            currenciesNeededAtPoint: towerCurrenciesNeededAtPoint,
            currenciesMadeAtPoint: towerCurrenciesMadeAtPoint,
            isDisabled: false,
            currenciesExistAtPoint: currenciesExistAtPoint,
            updateCurrencyDictWithStop: updateCurrencyDictWithStop,
            isPathEnd: (args["isPathEnd"] === undefined) ? false : args["isPathEnd"],
            convertExecutables: [ecs.makeParticleEffect(args)],
            checkFocusStopDisabled: checkFocusStopDisabled,
            risingTextKey: "risingText",
            requiredOpinions: (args["requiredOpinions"] === undefined) ? [] : args["requiredOpinions"],
            enableChecks: (args["enableChecks"] === undefined) ? [] : args["enableChecks"]
        };
    },
    conversation: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.conversation)));
        return ecs.trait(args);
    },
    criticizeSelfGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticizeSelfGoalConstruction)));
        return ecs.construction(args);
    },
    emotionSourceConstruction: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        args["killWithoutPath"] = true;
        return {
            focusPathStopComponent: ecs.constructionFocusPathStopComponent(args),
            rendererComponents: [ecs.constructionRenderComponent(args), ecs.progressRenderComponent(args)],
            personHeldComponent: ecs.personHeldComponent(args),
            managedComponent: ecs.managedComponent(args),
            constructionComponent: ecs.memoryConstructionComponent(args),
            createExecutables: [ecs.emotionSourceConstructionCreateExec(args)],
            junctionComponent: ecs.junctionComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            tickComponent: ecs.constructionTickComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.fixedPlayerMadeComponent(args)
        };
    },
    buildingUiActionComponent: function(args){
        return {
            getUiActions: getUiActions,
            generateUiActions: entityGenerateUiActions,
            memoizedActions: undefined
        };
    },
    pathMakerReplaceMarker: function(args){
        if (args.startKey === undefined){ throw "ECS fail " + args.key + " missing startKey"; }
        if (args.endKey === undefined){ throw "ECS fail " + args.key + " missing endKey"; }
        return {
            startKey: args['startKey'],
            endKey: args['endKey'],
            getReplaceKeys: pathMakerGetReplaceKeys
        };
    },
    flirtYouGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtYouGoalConstruction)));
        return ecs.construction(args);
    },
    takeConnectGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeConnectGoal)));
        return ecs.worldGoal(args);
    },
    askForBeliefGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askForBeliefGoalConstruction)));
        return ecs.construction(args);
    },
    insecureSwarmYouMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecureSwarmYouMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    hurting_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hurting_ext)));
        return ecs.sourceExtension(args);
    },
    workWinMajor: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.workWinMajor)));
        return ecs.instantEmotionResource(args);
    },
    solveProbeTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.solveProbeTowerConstruction)));
        return ecs.construction(args);
    },
    reinforceOldFailGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reinforceOldFailGoal)));
        return ecs.worldGoal(args);
    },
    openMenuMarkerComponent: function(args){
        if (args.entityUid === undefined){ throw "ECS fail " + args.key + " missing entityUid"; }
        return {
            entityUid: args['entityUid']
        };
    },
    flashback_criticismSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_criticismSmall)));
        return ecs.emotionResource(args);
    },
    workWinSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.workWinSmall)));
        return ecs.creep(args);
    },
    flirtHimMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtHimMenu)));
        return ecs.goalCompleteMenu(args);
    },
    hisBadWork_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisBadWork_ext)));
        return ecs.sourceExtension(args);
    },
    deriveWorkTopicMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.deriveWorkTopicMenu)));
        return ecs.goalCompleteMenu(args);
    },
    thinkMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.thinkMineConstruction)));
        return ecs.construction(args);
    },
    fishComplimentsGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.fishComplimentsGoalConstruction)));
        return ecs.construction(args);
    },
    spendTimeCleverButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeCleverButton)));
        return ecs.goalButton(args);
    },
    funPathYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.funPathYou)));
        return ecs.pathMaker(args);
    },
    sadAttack: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sadAttack)));
        return ecs.emotionSource(args);
    },
    takeSupportTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeSupportTowerConstruction)));
        return ecs.construction(args);
    },
    connectHurtBranch: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.connectHurtBranch)));
        return ecs.flagBranch(args);
    },
    goalButtonControlComponent: function(args){
        if (args.entityCost === undefined){ throw "ECS fail " + args.key + " missing entityCost"; }
        if (args.entityKey === undefined){ throw "ECS fail " + args.key + " missing entityKey"; }
        if (args.constructionKey === undefined){ throw "ECS fail " + args.key + " missing constructionKey"; }
        return {
            entityCost: args['entityCost'],
            aiVal: (args["aiVal"] === undefined) ? 0 : args["aiVal"],
            constructionKey: args['constructionKey'],
            checkMakePos: checkTowerMakePos,
            isNew: true,
            currenciesMade: (args["currenciesMade"] === undefined) ? [] : args["currenciesMade"],
            canMakeEntity: canMakeGoal,
            requiredEntities: (args["requiredEntities"] === undefined) ? [] : args["requiredEntities"],
            entityKey: args['entityKey'],
            wrappedFunction: undefined,
            disablingEntities: (args["disablingEntities"] === undefined) ? [] : args["disablingEntities"],
            managerKey: (args["managerKey"] === undefined) ? args.sourceKey : args["managerKey"],
            makeEntity: makeGoal,
            getAiVal: controlComponentGetAiVal,
            getWrappedFunction: getWrappedFunction,
            displayRiskIcon: (args["displayRiskIcon"] === undefined) ? false : args["displayRiskIcon"]
        };
    },
    depositComponent: function(args){
        if (args.deposit === undefined){ throw "ECS fail " + args.key + " missing deposit"; }
        return {
            deposit: args['deposit']
        };
    },
    workWinLarge: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.workWinLarge)));
        return ecs.creep(args);
    },
    switchCalmnessDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.switchCalmnessDeposit)));
        return ecs.switch(args);
    },
    fadingMemory: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.fadingMemory)));
        args["touchable"] = true;
        args["key"] = args.key + '_' + args.uid;
        args["health"] = (args["health"] === undefined) ? 2000 : args["health"];
        args["panelKey"] = (args["panelKey"] === undefined) ? PARAMETERS.traitPanel : args["panelKey"];
        return {
            uiActionComponent: ecs.buildingUiActionComponent(args),
            experienceComponent: ecs.experienceComponent(args),
            createExecutables: [ecs.builtSourceCreateExec(args), ecs.makeExtraPathsExec(args)],
            timedDeathComponent: ecs.timedDeathComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            entityManagerComponent: ecs.entityManagerComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            isaacEntityComponent: ecs.isaacEntityComponent(args),
            rendererComponents: [ecs.builtSourceRendererComponent(args)],
            focusTickResponseComponent: (args.aliveEntities) ? ecs.focusTickAliveMakerComponent(args) : undefined,
            menuCloseComponent: ecs.traitMenuCloseComponent(args),
            personHeldComponent: (args.personHeld) ? ecs.personHeldComponent(args) : undefined,
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killExtensions(args)],
            healthComponent: ecs.healthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            positionComponent: ecs.positionComponent(args),
            mapSpawnComponent: ecs.builtSourceMapSpawnComponent(args),
            fadingMemoryComponent: ecs.fadingMemoryComponent(args),
            junctionComponent: ecs.junctionComponent(args),
            playerMadeComponent: ecs.fixedPlayerMadeComponent(args)
        };
    },
    need: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.need)));
        return ecs.currency(args);
    },
    qualityRenderComponent: function(args){
        return {
            priority: 9,
            renderState: "default",
            render: qualityRender
        };
    },
    disabledTowerRenderComponent: function(args){
        return {
            priority: 6,
            image: "disabledTower",
            renderState: "default",
            render: disabledTowerRender
        };
    },
    worthlessPathNewRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worthlessPathNewRelationship)));
        return ecs.pathMaker(args);
    },
    makeSlowWorkSwarmButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeSlowWorkSwarmButton)));
        return ecs.goalButton(args);
    },
    himSupportTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.himSupportTowerConstruction)));
        return ecs.construction(args);
    },
    assertUniqueComponent: function(args){
        return {
            uniqueDuplicateEvent: assertUnique
        };
    },
    deposit: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        return {
            junctionComponent: ecs.junctionComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args), ecs.timedDeathRenderComponent(args)],
            uiActionComponent: ecs.buildingUiActionComponent(args),
            focusTickResponseComponent: ecs.aliveMakeComponent(args),
            depositComponent: ecs.depositComponent(args),
            managedComponent: (args.sourceTrait) ? ecs.managedComponent(args) : undefined,
            createExecutables: [ecs.checkMakeDeposit(args), ecs.depositPositionExec(args), ecs.makeExtraPathsExec(args), ecs.buildingConnectExec(args), (args.timeToDeath) ? ecs.timedDifficultyModifyExec(args) : undefined],
            focusPathStopComponent: ecs.depositFocusPathStopComponent(args),
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            clickComponent: ecs.fullMenuClickComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            tickComponent: ecs.depositTickComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    hardWorkButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hardWorkButton)));
        return ecs.goalButton(args);
    },
    connectHurtMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.connectHurtMenu)));
        return ecs.goalCompleteMenu(args);
    },
    oldFailFlat: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldFailFlat)));
        return ecs.instantEmotionResource(args);
    },
    trySomethingButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.trySomethingButton)));
        return ecs.goalButton(args);
    },
    stupidityFlat: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.stupidityFlat)));
        return ecs.instantEmotionResource(args);
    },
    positionComponent: function(args){
        return {
            planeOfExistence: (args["planeOfExistence"] === undefined) ? undefined : args["planeOfExistence"],
            setPos: setPos,
            comparePos: compComparePos,
            canBuildAtPos: trueFunction,
            isPos: isPos,
            y: assertPosition(args.y, 1),
            x: assertPosition(args.x, 0),
            getAsPos: getAsPos
        };
    },
    criticismAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismAction)));
        return ecs.currencyAction(args);
    },
    criticismMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismMed)));
        return ecs.creep(args);
    },
    focusPanelAbsolutePositionComponent: function(args){
        return {
            y: 678,
            x: 300,
            size: [300, 90]
        };
    },
    healthBleedTickComponent: function(args){
        return {
            tick: healthBleedTick
        };
    },
    cheerMineButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.cheerMineButton)));
        return ecs.memoryResourceButton(args);
    },
    askAboutRestlessMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askAboutRestlessMenu)));
        return ecs.goalCompleteMenu(args);
    },
    applyAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.applyAction)));
        return ecs.currencyAction(args);
    },
    truthAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.truthAction)));
        return ecs.currencyAction(args);
    },
    flirtHimGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtHimGoalConstruction)));
        return ecs.construction(args);
    },
    makeOldFailSwarmButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeOldFailSwarmButton)));
        return ecs.goalButton(args);
    },
    timedDeathComponent: function(args){
        if (args.timeToDeath === undefined){ throw "ECS fail " + args.key + " missing timeToDeath"; }
        return {
            killOnTimeOut: (args["killOnTimeOut"] === undefined) ? [] : args["killOnTimeOut"],
            timeToDeath: args['timeToDeath'],
            deathExecs: (args["deathExecs"] === undefined) ? [] : args["deathExecs"],
            makeOnTimeOut: (args["makeOnTimeOut"] === undefined) ? [] : args["makeOnTimeOut"]
        };
    },
    focusTickerComponent: function(args){
        return {
            ticks: 2,
            impulseTicks: 10
        };
    },
    memoryConstructionComponent: function(args){
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        return {
            constructionIdentifier: args['constructionIdentifier'],
            killWithoutPath: (args["killWithoutPath"] === undefined) ? false : args["killWithoutPath"],
            ticked: (args["ticked"] === undefined) ? false : args["ticked"],
            construct: memoryConstruct,
            currencyRequested: args['currencyRequested'],
            origCurrencyRequested: _.clone(args.currencyRequested),
            sourceKey: args['sourceKey']
        };
    },
    pointCounterNotificationComponent: function(args){
        return {
            notificationFunctions: simpleDict(PARAMETERS.addPoints, addPoints),
            serializeComponent: ecs.notificationSerializeComponent(args)
        };
    },
    beSupportedDone: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.beSupportedDone)));
        return ecs.endGoal(args);
    },
    setFlag: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.setFlagExec(args), ecs.killEntity(args)]
        };
    },
    buttonUiActionComponent: function(args){
        return {
            getUiActions: getUiActions,
            inspectFunction: undefined,
            generateUiActions: buttonGenerateUiActions,
            memoizedActions: undefined
        };
    },
    warmPathSelfish: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.warmPathSelfish)));
        return ecs.pathMaker(args);
    },
    callousnessTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.callousnessTower)));
        return ecs.tower(args);
    },
    changeOpinionExec: function(args){
        return {
            execute: changeOpinion,
            opinionToAdd: (args["opinionToAdd"] === undefined) ? undefined : args["opinionToAdd"],
            opinionToRemove: (args["opinionToRemove"] === undefined) ? undefined : args["opinionToRemove"]
        };
    },
    rechargeButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.rechargeButton)));
        return ecs.memoryTowerButton(args);
    },
    oldFail: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldFail)));
        return ecs.currency(args);
    },
    makeComplimentSwarmButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeComplimentSwarmButton)));
        return ecs.goalButton(args);
    },
    chapter1: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.chapter1)));
        return ecs.gameStage(args);
    },
    hisGraciousGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisGraciousGoal)));
        return ecs.worldGoal(args);
    },
    aloneFlatYouMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.aloneFlatYouMine)));
        return ecs.emotionResource(args);
    },
    himPathHimself: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.himPathHimself)));
        return ecs.pathMaker(args);
    },
    mistrustJoyAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.mistrustJoyAction)));
        return ecs.currencyAction(args);
    },
    feedCrisisResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.feedCrisisResult)));
        return ecs.randomReplace(args);
    },
    flipClever: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flipClever)));
        return ecs.pairTransform(args);
    },
    holdableComponent: function(args){
        return {
            held: false
        };
    },
    memory_shameBurst: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_shameBurst)));
        return ecs.memory(args);
    },
    trainPathHelpInfoPanel: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.trainPathHelpInfoPanel)));
        return ecs.helpInfoPanel(args);
    },
    killConnectFriendsButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.killConnectFriendsButton)));
        return ecs.entityKill(args);
    },
    lostControl: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.lostControl)));
        return {
            createExecutables: [ecs.makeGainControlMenuExec(args), ecs.timeForceExec(args)],
            holdControlComponent: ecs.holdControlComponent(args),
            killExecutables: [ecs.lostControlDeathExec(args)],
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            identityComponent: ecs.identityComponent(args),
            timeForceComponent: ecs.timeForceComponent(args)
        };
    },
    onTraitComponent: function(args){
        return {
            execute: memoryGoalCompleteExec,
            bonusTime: (args["bonusTime"] === undefined) ? 30 : args["bonusTime"],
            flareMemory: (args["flareMemory"] === undefined) ? false : args["flareMemory"],
            killMemory: (args["killMemory"] === undefined) ? false : args["killMemory"]
        };
    },
    takeConnectButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeConnectButton)));
        return ecs.goalButton(args);
    },
    flaggedMakeReplaceMarker: function(args){
        if (args.flagToCheck === undefined){ throw "ECS fail " + args.key + " missing flagToCheck"; }
        if (args.entitiesToMake === undefined){ throw "ECS fail " + args.key + " missing entitiesToMake"; }
        return {
            flagToCheck: args['flagToCheck'],
            entitiesToMake: args['entitiesToMake'],
            getReplaceKeys: flaggedMakeGetReplaceKeys
        };
    },
    emotionSourceComponent: function(args){
        return {
            emotions: unrollDict(args.emotionsToAdd)
        };
    },
    worldGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worldGoal)));
        args["touchable"] = true;
        args["particleKey"] = PARAMETERS.newParticle;
        args["canExpandInto"] = false;
        args["playerKillable"] = !!(args.constructed);
        args["killOnTransform"] = (args["killOnTransform"] === undefined) ? true : args["killOnTransform"];
        return {
            uiActionComponent: ecs.buildingUiActionComponent(args),
            goalTrackComponent: ecs.checkWorldGoalComponent(args),
            createExecutables: [ecs.checkManagedComponentExec(args), (args.randomPosition) ? ecs.randomOpenPositionExec(args) : undefined, ecs.makeExtraPathsExec(args), ecs.chkForPlayerInterrupt(args), ecs.buildingConnectExec(args), (args.timeToDeath) ? ecs.timedDifficultyModifyExec(args) : undefined],
            timedDeathComponent: (args.timeToDeath) ? ecs.worldGoalTimedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            rendererComponents: [ecs.worldGoalRenderComponent(args), ecs.progressRenderComponent(args), ecs.timedDeathRenderComponent(args)],
            focusTickResponseComponent: (args.aliveEntities) ? ecs.aliveMakeComponent(args) : undefined,
            managedComponent: (args.sourceTrait) ? ecs.managedComponent(args) : undefined,
            flipComponent: (args.flipEntity) ? ecs.flipComponent(args) : undefined,
            worldGoalComponent: ecs.worldGoalComponent(args),
            focusPathStopComponent: ecs.worldGoalFocusPathStopComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            uniqueComponent: ecs.uniqueComponent(args),
            positionComponent: ecs.positionComponent(args),
            notificationComponents: [ecs.worldGoalNotificationComponent(args)],
            junctionComponent: ecs.junctionComponent(args),
            pauseComponent: ecs.pauseComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    willMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.willMine)));
        return ecs.resource(args);
    },
    strongPathMature: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.strongPathMature)));
        return ecs.pathMaker(args);
    },
    flagBranchReplaceMarker: function(args){
        if (args.flagToCheck === undefined){ throw "ECS fail " + args.key + " missing flagToCheck"; }
        return {
            flagToCheck: args['flagToCheck'],
            flagEntities: (args["flagEntities"] === undefined) ? [] : args["flagEntities"],
            getReplaceKeys: flagBranchGetReplaceKeys,
            notFlagEntities: (args["notFlagEntities"] === undefined) ? [] : args["notFlagEntities"]
        };
    },
    addPersonAndOpinionExec: function(args){
        if (args.personKey === undefined){ throw "ECS fail " + args.key + " missing personKey"; }
        if (args.opinionKey === undefined){ throw "ECS fail " + args.key + " missing opinionKey"; }
        return {
            opinionKey: args['opinionKey'],
            execute: addPersonAndOpinionExec,
            personKey: args['personKey']
        };
    },
    randomReplace: function(args){
        return {
            replaceMarker: ecs.randomReplaceMarker(args)
        };
    },
    warm_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.warm_ext)));
        return ecs.sourceExtension(args);
    },
    dayPanelAbsolutePositionComponent: function(args){
        return {
            y: 678,
            x: 0,
            size: [300, 90]
        };
    },
    restless_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.restless_ext)));
        return ecs.sourceExtension(args);
    },
    flipComponent: function(args){
        if (args.flipEntity === undefined){ throw "ECS fail " + args.key + " missing flipEntity"; }
        return {
            flipEntity: args['flipEntity']
        };
    },
    state: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.state)));
        return ecs.currency(args);
    },
    personHealAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.personHealAction)));
        args["personHeld"] = args.source.personHeldComponent.personHeld;
        return {
            healthComponent: ecs.healthComponent(args),
            personHeldComponent: ecs.personHeldComponent(args),
            createExecutables: [ecs.personRelationshipExec(args)]
        };
    },
    dreamDeathMajor: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.dreamDeathMajor)));
        return ecs.instantEmotionResource(args);
    },
    takeConnectGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeConnectGoalConstruction)));
        return ecs.construction(args);
    },
    anxietyMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.anxietyMine)));
        return ecs.resource(args);
    },
    speakOfValueButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.speakOfValueButton)));
        return ecs.goalButton(args);
    },
    joy: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.joy)));
        return ecs.creep(args);
    },
    socialMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialMine)));
        return ecs.resource(args);
    },
    flashback_aloneMedConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_aloneMedConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    supportNeedTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportNeedTower)));
        return ecs.tower(args);
    },
    doUsefulMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.doUsefulMenu)));
        return ecs.goalCompleteMenu(args);
    },
    memory_viceFlatYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_viceFlatYou)));
        return ecs.memory(args);
    },
    searchingWorthToHelpful: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.searchingWorthToHelpful)));
        return ecs.transformExec(args);
    },
    flashback_anger: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_anger)));
        return ecs.emotionResource(args);
    },
    complimentFlatYouMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentFlatYouMine)));
        return ecs.emotionResource(args);
    },
    needBusyTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.needBusyTowerConstruction)));
        return ecs.construction(args);
    },
    forceOpennessButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.forceOpennessButton)));
        return ecs.goalButton(args);
    },
    generousTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.generousTowerConstruction)));
        return ecs.construction(args);
    },
    slowWorkMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.slowWorkMed)));
        return ecs.creep(args);
    },
    flirtYouMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flirtYouMenu)));
        return ecs.goalCompleteMenu(args);
    },
    transformExec: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.transformTrait(args), ecs.killEntity(args)]
        };
    },
    caringAction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.caringAction)));
        return ecs.currencyAction(args);
    },
    reinforceViceGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.reinforceViceGoal)));
        return ecs.worldGoal(args);
    },
    viceMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.viceMed)));
        return ecs.creep(args);
    },
    maturePathHisWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.maturePathHisWork)));
        return ecs.pathMaker(args);
    },
    findHelpResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findHelpResult)));
        return ecs.randomReplace(args);
    },
    goodSpendTimeResult: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goodSpendTimeResult)));
        return ecs.entityReplace(args);
    },
    talkAboutHimGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkAboutHimGoalConstruction)));
        return ecs.construction(args);
    },
    quietTimeButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.quietTimeButton)));
        return ecs.goalButton(args);
    },
    complimentSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentSmall)));
        return ecs.creep(args);
    },
    checkWorldGoalComponent: function(args){
        return {
            successExecutables: [ecs.goalCompleteExec(args)].concat([ecs.trackActionables(args), ecs.makeEntityComponent(args), ecs.makeGoalMenuExecutable(args)]),
            checkCompleted: checkWorldGoalComponent
        };
    },
    entityKill: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            createExecutables: [ecs.killEntityComponent(args), ecs.killEntity(args)]
        };
    },
    insecureSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.insecureSmall)));
        return ecs.creep(args);
    },
    value: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.value)));
        return ecs.currency(args);
    },
    cursor: function(args){
        return {
            rendererComponents: [ecs.cursorRenderComponent(args)]
        };
    },
    oldLifeMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldLifeMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    hardWorkMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hardWorkMenu)));
        return ecs.goalCompleteMenu(args);
    },
    probedProblemDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.probedProblemDeposit)));
        return ecs.deposit(args);
    },
    connectHurtButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.connectHurtButton)));
        return ecs.goalButton(args);
    },
    searchWorthButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.searchWorthButton)));
        return ecs.goalButton(args);
    },
    flashback_complimentMedConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_complimentMedConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    sharePainGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.sharePainGoalConstruction)));
        return ecs.construction(args);
    },
    anxietyMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.anxietyMineConstruction)));
        return ecs.construction(args);
    },
    makeWorkWinMajorGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeWorkWinMajorGoal)));
        return ecs.worldGoal(args);
    },
    experienceTriggerComponent: function(args){
        if (args.traitKey === undefined){ throw "ECS fail " + args.key + " missing traitKey"; }
        if (args.xpEntities === undefined){ throw "ECS fail " + args.key + " missing xpEntities"; }
        return {
            traitKey: args['traitKey'],
            xpEntities: args['xpEntities']
        };
    },
    joyBurst: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.joyBurst)));
        return ecs.emotionSource(args);
    },
    criticismSwarmYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.criticismSwarmYou)));
        return ecs.emotionSource(args);
    },
    builtSourceRendererComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            outlineImage: "activeOutline",
            render: builtSourceRender,
            wobble: 0,
            image: args['image'],
            priority: 5,
            timeToBlink: 1,
            newImage: "newOutline",
            getWobble: getWobble,
            renderState: "default",
            disabledImage: "trait-aaaaaa"
        };
    },
    gainControlMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.gainControlMenu)));
        args["size"] = [550, 350];
        return {
            healthComponent: ecs.singleHealthComponent(args),
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            rendererComponents: [ecs.gainControlMenuRender(args)],
            killExecutables: [ecs.killLostControlExec(args)]
        };
    },
    killWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.killWork)));
        return ecs.entityKill(args);
    },
    flashback_guiltMed: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_guiltMed)));
        return ecs.emotionResource(args);
    },
    worldGoalNotificationComponent: function(args){
        return {
            notificationFunctions: simpleDict(PARAMETERS.openMenu, worldGoalMenuOpened),
            serializeComponent: ecs.notificationSerializeComponent(args)
        };
    },
    thought: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.thought)));
        return ecs.currency(args);
    },
    chore: function(args){
        return {
            replaceMarker: ecs.choreReplaceMarker(args)
        };
    },
    caringTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.caringTower)));
        return ecs.tower(args);
    },
    openUpButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.openUpButton)));
        return ecs.goalButton(args);
    },
    traitPanelRenderComponent: function(args){
        return {
            insetColor: "#000000",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "uiBack",
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            priority: 18,
            render: traitPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            currentCategory: undefined,
            setCategoryFn: {},
            renderTime: 0,
            baseSize: args['size'],
            textColor: "#000000",
            renderState: "default",
            specificRender: args['specificRender'],
            drawHelpButton: drawHelpButton
        };
    },
    personResourceButton: function(args){
        args["subPanel"] = (args["subPanel"] === undefined) ? "Towers" : args["subPanel"];
        args["multiTrait"] = (args["multiTrait"] === undefined) ? false : args["multiTrait"];
        return {
            interactionComponent: ecs.interactionComponent(args),
            uiActionComponent: ecs.buttonUiActionComponent(args),
            buttonControlComponent: ecs.towerControlComponent(args),
            personHeldComponent: ecs.personHeldComponent(args),
            createExecutables: [ecs.markTraitNew(args)],
            timedDeathComponent: (args.timeToDeath) ? ecs.timedDeathComponent(args) : undefined,
            uiDataComponent: ecs.uiDataComponent(args),
            uniqueComponent: (args.timeToDeath === undefined && !args.multiTrait) ? ecs.uniqueComponent(args) : undefined,
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            killExecutables: [ecs.killTowerButtonExec(args)],
            identityComponent: ecs.identityComponent(args)
        };
    },
    emotionSourceConstructionCreateExec: function(args){
        if (args.sourceKey === undefined){ throw "ECS fail " + args.key + " missing sourceKey"; }
        return {
            focusStopKey: "impulse",
            execute: emotionSourceConstructionCreateExec,
            trainPath: PARAMETERS.singleUseTrainPath,
            sourceKey: args['sourceKey']
        };
    },
    pushInsecurityGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.pushInsecurityGoal)));
        return ecs.worldGoal(args);
    },
    rejectMeanlessMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.rejectMeanlessMenu)));
        return ecs.goalCompleteMenu(args);
    },
    flashback_complimentSmallConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_complimentSmallConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    callousnessButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.callousnessButton)));
        return ecs.towerButton(args);
    },
    gameEndComponent: function(args){
        return {
            gameEnded: true
        };
    },
    beHelpGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.beHelpGoal)));
        return ecs.worldGoal(args);
    },
    getFeedbackMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.getFeedbackMenu)));
        return ecs.goalCompleteMenu(args);
    },
    youInfoDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.youInfoDeposit)));
        return ecs.deposit(args);
    },
    oldHurtMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.oldHurtMine)));
        return ecs.emotionResource(args);
    },
    pathMoveComponent: function(args){
        return {
            startPosition: args['start'],
            ticks: 1,
            endPosition: args['end']
        };
    },
    helpInfoPanelRenderComponent: function(args){
        if (args.helpLines === undefined){ throw "ECS fail " + args.key + " missing helpLines"; }
        return {
            drawPanelButton: drawPanelButton,
            insetColor: "#000000",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "uiBack",
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            priority: 24,
            render: outPanelRender,
            helpLines: args['helpLines'],
            snapPanelPos: snapPanelPos,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            specificRender: helpInfoPanelRender,
            drawHelpButton: drawHelpButton
        };
    },
    selfEsteemDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfEsteemDeposit)));
        return ecs.deposit(args);
    },
    acceptConnectionYouMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.acceptConnectionYouMenu)));
        return ecs.goalCompleteMenu(args);
    },
    cheerMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.cheerMineConstruction)));
        return ecs.memoryConstruction(args);
    },
    memoryFade: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            timedDeathComponent: ecs.timedDeathComponent(args),
            memoryFadeComponent: ecs.memoryFadeComponent(args),
            killExecutables: [ecs.memoryFadeExec(args)]
        };
    },
    speakOfValueGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.speakOfValueGoalConstruction)));
        return ecs.construction(args);
    },
    starParticleEffect: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            lifeSentinelComponent: ecs.sourceLifeSentinelComponent(args),
            rendererComponents: [ecs.starParticleEffectRenderComponent(args)]
        };
    },
    helpful: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.helpful)));
        return ecs.trait(args);
    },
    trySomethingGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.trySomethingGoal)));
        return ecs.worldGoal(args);
    },
    replaceMarker: function(args){
        if (args.getReplaceKeys === undefined){ throw "ECS fail " + args.key + " missing getReplaceKeys"; }
        return {
            getReplaceKeys: args['getReplaceKeys']
        };
    },
    askAboutRestlessButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askAboutRestlessButton)));
        return ecs.goalButton(args);
    },
    worthlessSmall: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.worthlessSmall)));
        return ecs.creep(args);
    },
    demolishButtonRenderComponent: function(args){
        return {
            priority: 2,
            renderState: "default",
            render: demolishButtonRender,
            demolishButtonFunction: undefined
        };
    },
    guiltGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.guiltGoalConstruction)));
        return ecs.construction(args);
    },
    qualityResource: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        args["quality"] = (args["quality"] === undefined) ? Math.floor(Math.random() * 3) + 2 : args["quality"];
        return {
            focusPathStopComponent: ecs.resourceFocusPathStopComponent(args),
            rendererComponents: [ecs.pathStopRenderComponent(args)].concat([ecs.qualityRenderComponent(args)]),
            qualityComponent: ecs.qualityComponent(args),
            focusTickResponseComponent: ecs.resourceFocusTickResponseComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            managedComponent: ecs.managedComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)],
            resourceComponent: ecs.resourceComponent(args),
            junctionComponent: ecs.junctionComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            killExecutables: [ecs.killResourceCurrencies(args)],
            tickComponent: ecs.qualityResourceTickComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    findLifeHelpGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findLifeHelpGoal)));
        return ecs.worldGoal(args);
    },
    goalCompleteMenu: function(args){
        args["y"] = 5;
        args["x"] = width / 2 - 325;
        args["size"] = [650, 600];
        return {
            rendererComponents: [ecs.goalCompleteMenuRender(args)],
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            uiClickComponent: ecs.panelUiClickComponent(args),
            createExecutables: [ecs.goalCompleteMenuCreateExec(args)],
            goalCompleteMenuComponent: ecs.goalCompleteMenuComponent(args),
            panelComponent: ecs.goalCompleteMenuPanelComponent(args),
            pauseComponent: ecs.pauseComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            rebuildMenuComponent: ecs.rebuildMenuComponent(args),
            identityComponent: ecs.identityComponent(args)
        };
    },
    selfishPathRelationship: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfishPathRelationship)));
        return ecs.pathMaker(args);
    },
    killEntity: function(args){
        return {
            execute: killEntity
        };
    },
    choreGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.choreGoal)));
        return ecs.worldGoal(args);
    },
    tryForConnectionHimMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.tryForConnectionHimMenu)));
        return ecs.goalCompleteMenu(args);
    },
    topicDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.topicDeposit)));
        return ecs.deposit(args);
    },
    menuTutorialText: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            tutorialTextComponent: ecs.menuTutorialTextComponent(args),
            absolutePositionComponent: ecs.absolutePositionComponent(args),
            rendererComponents: [ecs.menuTutorialTextRenderComponent(args)]
        };
    },
    damageRenderComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            priority: 7,
            image: args['image'],
            renderState: "default",
            render: damageRender,
            blinkTimer: 0
        };
    },
    exploreStrengthGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.exploreStrengthGoalConstruction)));
        return ecs.construction(args);
    },
    beSupportedMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.beSupportedMenu)));
        return ecs.goalCompleteMenu(args);
    },
    makeDreamDeathMajorGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeDreamDeathMajorGoal)));
        return ecs.worldGoal(args);
    },
    socialWarmMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialWarmMine)));
        return ecs.resource(args);
    },
    friendMeditateTowerConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.friendMeditateTowerConstruction)));
        return ecs.construction(args);
    },
    emotionTickModifyComponent: function(args){
        if (args.towerTrait === undefined){ throw "ECS fail " + args.key + " missing towerTrait"; }
        if (args.emotionState === undefined){ throw "ECS fail " + args.key + " missing emotionState"; }
        if (args.factor === undefined){ throw "ECS fail " + args.key + " missing factor"; }
        return {
            towerTrait: args['towerTrait'],
            emotionState: args['emotionState'],
            factor: args['factor']
        };
    },
    flashback_criticismSmallConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.flashback_criticismSmallConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    obsessGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessGoal)));
        return ecs.worldGoal(args);
    },
    askHelpGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.askHelpGoal)));
        return ecs.worldGoal(args);
    },
    joyBurstMineConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.joyBurstMineConstruction)));
        return ecs.emotionSourceConstruction(args);
    },
    complimentYouGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.complimentYouGoalConstruction)));
        return ecs.construction(args);
    },
    holdControlComponent: function(args){
        return {
            holdControl: true
        };
    },
    completeWorkDeposit: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.completeWorkDeposit)));
        return ecs.deposit(args);
    },
    giveInButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.giveInButton)));
        return ecs.goalButton(args);
    },
    talkAboutYouGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.talkAboutYouGoal)));
        return ecs.worldGoal(args);
    },
    nextDayEntityDayResponseComponent: function(args){
        return {
            dayChange: (args["dayChange"] === undefined) ? undefined : args["dayChange"],
            dayEnd: nextDayEntityDayEnd,
            dayStart: (args["dayStart"] === undefined) ? undefined : args["dayStart"],
            execs: [ecs.makeEntityComponent(args), ecs.killEntityComponent(args)]
        };
    },
    setRelation: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.setRelation)));
        return ecs.setFlag(args);
    },
    supportCrisisGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.supportCrisisGoal)));
        return ecs.worldGoal(args);
    },
    resourceModifier: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.resourceModifier)));
        return {
            healthComponent: ecs.singleHealthComponent(args),
            resourceModifierComponent: ecs.resourceModifierComponent(args),
            rendererComponents: [ecs.resourceModifierRenderComponent(args)],
            dayResponseComponent: ecs.killDayEndComponent(args),
            timedDeathComponent: ecs.timedDeathComponent(args)
        };
    },
    trainPanelRenderComponent: function(args){
        return {
            arrowImage: "trainPathArrow",
            insetColor: "#000000",
            fullAnimationTime: 0.1,
            yTextOffset: 5,
            backImage: "uiBack",
            isConnectingTrack: false,
            drawImageButton: drawImageButton,
            animatingTime: 0.1,
            priority: 18,
            render: outPanelRender,
            drawPanelButton: drawPanelButton,
            snapPanelPos: snapPanelPos,
            renderTime: 0,
            textColor: "#000000",
            renderState: "default",
            specificRender: trainPanelRender,
            drawHelpButton: drawHelpButton
        };
    },
    makeComplimentFlatButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeComplimentFlatButton)));
        return ecs.goalButton(args);
    },
    feedCrisisGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.feedCrisisGoal)));
        return ecs.worldGoal(args);
    },
    dayCounterComponent: function(args){
        args["ticks"] = PARAMETERS.dayTicks;
        if (args.ticks === undefined){ throw "ECS fail " + args.key + " missing ticks"; }
        return {
            dayCount: (args["dayCount"] === undefined) ? 1 : args["dayCount"],
            ticks: args['ticks'],
            getPartOfDay: getPartOfDay,
            impulseTicks: args['ticks']
        };
    },
    killStartRelationHimButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.killStartRelationHimButton)));
        return ecs.entityKill(args);
    },
    frustration: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.frustration)));
        return ecs.currency(args);
    },
    makeStupidityFlatGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeStupidityFlatGoal)));
        return ecs.worldGoal(args);
    },
    focusCostComponent: function(args){
        return {
            focusCost: (args["focusCost"] === undefined) ? 1 : args["focusCost"]
        };
    },
    paramPathExec: function(args){
        if (args.startKey === undefined){ throw "ECS fail " + args.key + " missing startKey"; }
        if (args.endKey === undefined){ throw "ECS fail " + args.key + " missing endKey"; }
        return {
            startKey: args['startKey'],
            execute: paramPathExec,
            trainPathKey: PARAMETERS.trainPath,
            endKey: args['endKey']
        };
    },
    noSupportMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.noSupportMenu)));
        return ecs.goalCompleteMenu(args);
    },
    construction: function(args){
        args["touchable"] = true;
        args["canExpandInto"] = false;
        return {
            junctionComponent: ecs.junctionComponent(args),
            rendererComponents: [ecs.constructionRenderComponent(args), ecs.progressRenderComponent(args)],
            personHeldComponent: ecs.personHeldComponent(args),
            managedComponent: ecs.managedComponent(args),
            constructionComponent: ecs.constructionComponent(args),
            createExecutables: [ecs.makeExtraPathsExec(args)].concat([ecs.openMenu(args)]),
            focusPathStopComponent: ecs.constructionFocusPathStopComponent(args),
            clickComponent: ecs.fullMenuClickComponent(args),
            uiDataComponent: ecs.uiDataComponent(args),
            tickComponent: ecs.constructionTickComponent(args),
            descriptionComponent: ecs.descriptionComponent(args),
            healthComponent: ecs.singleHealthComponent(args),
            interactionComponent: ecs.interactionComponent(args),
            identityComponent: ecs.identityComponent(args),
            positionComponent: ecs.positionComponent(args),
            playerMadeComponent: ecs.playerMadeComponent(args)
        };
    },
    socialCleverMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.socialCleverMine)));
        return ecs.resource(args);
    },
    failMakeEntityComponent: function(args){
        args["failEntities"] = (args["failEntities"] === undefined) ? [] : args["failEntities"];
        return {
            execute: executeMakeEntities,
            entitiesToMake: args['failEntities'],
            adjacent: (args["adjacent"] === undefined) ? false : args["adjacent"]
        };
    },
    trainPathMenuCloseComponent: function(args){
        return {
            execute: trainPathMenuCloseExec
        };
    },
    caringButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.caringButton)));
        return ecs.towerButton(args);
    },
    memory_complimentSwarmYou: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.memory_complimentSwarmYou)));
        return ecs.memory(args);
    },
    critical_ext: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.critical_ext)));
        return ecs.sourceExtension(args);
    },
    findUsefulGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.findUsefulGoalConstruction)));
        return ecs.construction(args);
    },
    distract: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.distract)));
        return ecs.currency(args);
    },
    relationshipMine: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.relationshipMine)));
        return ecs.resource(args);
    },
    carriage: function(args){
        return {
            healthComponent: ecs.singleHealthComponent(args),
            positionComponent: ecs.positionComponent(args),
            carriageComponent: ecs.carriageComponent(args)
        };
    },
    quietCriticismGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.quietCriticismGoal)));
        return ecs.worldGoal(args);
    },
    hisWork: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.hisWork)));
        return ecs.trait(args);
    },
    goodness: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.goodness)));
        return ecs.currency(args);
    },
    rejectMeanlessGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.rejectMeanlessGoalConstruction)));
        return ecs.construction(args);
    },
    towerCreateExec: function(args){
        return {
            execute: towerCreateExec
        };
    },
    makeStupidityFlatButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeStupidityFlatButton)));
        return ecs.goalButton(args);
    },
    spendTimeCleverMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.spendTimeCleverMenu)));
        return ecs.goalCompleteMenu(args);
    },
    killDefineRoleButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.killDefineRoleButton)));
        return ecs.entityKill(args);
    },
    fullMenuClickComponent: function(args){
        if (args.image === undefined){ throw "ECS fail " + args.key + " missing image"; }
        return {
            image: args['image'],
            onClick: fullMenuOnClick,
            uiKey: (args["uiKey"] === undefined) ? getUiKey(args.key, args.uid) : args["uiKey"],
            panelKey: (args["panelKey"] === undefined) ? PARAMETERS.towerPanel : args["panelKey"]
        };
    },
    startRelationYouMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.startRelationYouMenu)));
        return ecs.goalCompleteMenu(args);
    },
    makeComplimentSwarmGoalConstruction: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.makeComplimentSwarmGoalConstruction)));
        return ecs.construction(args);
    },
    doFunGoal: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.doFunGoal)));
        return ecs.worldGoal(args);
    },
    takeConnectBranch: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.takeConnectBranch)));
        return ecs.flagBranch(args);
    },
    obsessionsTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessionsTower)));
        return ecs.tower(args);
    },
    cruelty: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.cruelty)));
        return ecs.currency(args);
    },
    solveProbeButton: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.solveProbeButton)));
        return ecs.towerButton(args);
    },
    stageChangeComponent: function(args){
        if (args.goalsToCheck === undefined){ throw "ECS fail " + args.key + " missing goalsToCheck"; }
        return {
            executables: [ecs.makeEntityComponent(args), ecs.killEntityComponent(args)],
            shouldChange: false,
            checkAndChange: checkAndChangeGameState,
            goalsToCheck: args['goalsToCheck']
        };
    },
    selfValueTower: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.selfValueTower)));
        return ecs.tower(args);
    },
    faithCrisis: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.faithCrisis)));
        return ecs.trait(args);
    },
    obsessMenu: function(args){
        updateArgs(args, JSON.parse(JSON.stringify(allArgs.obsessMenu)));
        return ecs.goalCompleteMenu(args);
    }
};


var setAbsPosFromRect = function(rect){
    this.x = rect[0];
    this.y = rect[1];
    this.size[0] = rect[2];
    this.size[1] = rect[3];
};

var getAbsPosRect = function(){
    return [this.x, this.y, this.size[0], this.size[1]];
};


var activateRender = function(rect){
    if (this.activated){
        ctx.drawImage(getImage('activeHex'), rect[0], rect[1]);
        this.activated = false;
    }
}


var addPersonAndOpinionExec = function(entity, world){
    var person = world.entityForKey(this.personKey);
    if (!person){
        person = makeEcs(this.personKey);
        var pos = world.randomOpenPosition(person.positionComponent.planeOfExistence);
        person.positionComponent.x = pos[0];
        person.positionComponent.y = pos[1];
        world.addEntity(person);
    }

    person.personalityComponent.addOpinionToPersonality(this.opinionKey, person, world);
    entity.healthComponent.health = 0;
};


var aliveMakeFocusTick = function(entity, world){
    world.makeEntities(entity, this.aliveEntities);
};


var allBuildingPanelRender = function(rect, entity, ui){
    var buttonRect;
    if (!this.pageUpFunction){
        this.pageUpFunction = () => {
            this.page -= 1;
            this.page = max(this.page, 1);
            this.currentCategory = undefined;
        };

        this.pageDownFunction = () => {
            this.page += 1;
            this.currentCategory = undefined;
        };
    }

    var panelButtons = [];
    var world = ui.world;

    var buttons = _.chain(world.entities)
        .filter(function(worldEntity){
            return worldEntity.buttonControlComponent;
        })
        .groupBy(function(worldEntity){
            return worldEntity.buttonControlComponent.managerKey;
        })
        .value();

    var maxPage = Object.keys(buttons).length;
    this.page = min(this.page, maxPage);

    var lineCount = _.reduce(buttons, function(memo, val, key){
        return memo + val.length + 1;
    }, 0);
    
    entity.absolutePositionComponent.size[1] = 650;
    rect = entity.absolutePositionComponent.getAbsPosRect();

    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);

    ctx.fillStyle = this.textColor;
    ctx.font = getFont(28);

    var title = 'Buildings';
    var titleWidth = ctx.measureText(title).width;

    ctx.fillText(title, rect[0] + (rect[2] - titleWidth) / 2, rect[1] + 60);

    var y = rect[1] + 150;
    ctx.font = getFont(18);
    ctx.strokeStyle = this.insetColor;

    var buttonsOnPage = 0;
    var traitPage = 0;

    _.each(buttons, (btns, trait) => {
        traitPage += 1;
        
        if (traitPage != this.page){
            return;
        }

        var traitImage = getImage(allArgs[trait].image);
        ctx.drawImage(traitImage, rect[0] + 10, y - 38);

        ctx.font = getFont(24);
        ctx.fillText(sanitize(trait), rect[0] + 80, y);
        ctx.font = getFont(18);
        y += 50;

        var traitEntity = world.entityForKey(trait);

        if (traitEntity.entityManagerComponent.disabled){
            var disablingEntity = _.chain(world.entities)
                .filter(worldEntity => (worldEntity.disableTraitComponent && 
                                        worldEntity.disableTraitComponent.checkTraitDisabled(traitEntity)))
                .first()
                .value();
            ctx.fillText('Disabled: ' + disablingEntity.identityComponent.name, rect[0] + 30, y);
            y += 50;
            return;
        }
        
        var categories = _.chain(btns)
            .map(function(button){ return button.uiDataComponent.subPanel; })
            .uniq()
            .sortBy(_.identity)
            .reverse()
            .value();

        if (this.currentCategory === undefined){
            this.currentCategory = categories[0];
        }

        _.each(categories, (panelKey, i) => {
            var x = rect[0] + 10 + 130 * i;
            if (panelKey == this.currentCategory){
                ctx.fillText(panelKey, x, y - 10);
                ctx.fillRect(x, y - 5, 70, 2);
            }
            else{
                var panelRect = [x, y - 30, 100, 30];
                this.drawPanelButton(panelRect, panelKey);

                if (!this.setCategoryFn[panelKey]){
                    this.setCategoryFn[panelKey] = () => {
                        this.currentCategory = panelKey;
                    };
                }
                var setCategoryFn = this.setCategoryFn[panelKey];
                panelButtons.push([panelRect, setCategoryFn]);
            }
        });

        btns = _.filter(btns, (button) => {
            return button.uiDataComponent.subPanel == this.currentCategory;
        });

        ctxRoundedRect([rect[0] + 5, y + 5, rect[2] - 10, 60 * btns.length + 20]);

        y += 50;

        _.each(btns, (button) => {
            ctx.font = getFont((button.identityComponent.name.length > 17) ? 14 : 18);

            ctx.drawImage(traitImage, rect[0] + 20, y - 38);
            ctx.drawImage(getImage(button.uiDataComponent.image), rect[0] + 20, y - 38);
            
            ctx.fillText(button.identityComponent.name, rect[0] + 80, y);

            ctx.font = '12px OpenSansItalic';
            if (_.isArray(button.descriptionComponent.description)){
                _.each(button.descriptionComponent.description, (desc, i) => {
                    ctx.fillText(desc, rect[0] + 260, y - 7 + 15 * i);
                });
            }
            else{
                ctx.fillText(button.descriptionComponent.description, rect[0] + 260, y - 2);
            }
            ctx.font = getFont(20);

            var x = rect[0] + rect[2] - 180;

            if (!_.contains(traitEntity.interactionComponent.connectionKeys, PARAMETERS.self)){
                var start = world.entityForKey(PARAMETERS.self).positionComponent.getAsPos();
                var end = traitEntity.positionComponent.getAsPos();
                if (determinePath(start, end, world.getAllPaths())){
                    traitEntity.interactionComponent.connectionKeys.push(PARAMETERS.self);
                }
            }

            if (button.interactionComponent.canInteractSelf() && _.contains(traitEntity.interactionComponent.connectionKeys, PARAMETERS.self)){
                var uiActions = button.uiActionComponent.getUiActions(button, ui, entity);

                _.each(uiActions, (fn, key) => {
                    buttonRect = [x, y - 30, 80, 35];
                    this.drawPanelButton(buttonRect, key);
                    panelButtons.push([buttonRect, fn]);
                    
                    x += 90;
                });

                if (!uiActions['Build']){
                    ctx.font = getFont(14);
                    ctx.fillText('Limit', x, y - 15);
                    ctx.fillText('Reached', x, y);
                    ctx.font = getFont(20);
                }
            }
            else{
                ctx.fillText('No Control', x, y - 10);
            }
                
            y += 60;
        });
    });

    ctx.font = BASE_FONT;

    y = rect[1] + rect[3] - 100;

    if (lineCount > 6){
        if (this.page > 1){
            buttonRect = [rect[0] + 10, y, 100, 40];
            this.drawPanelButton(buttonRect, 'Page Up');
            panelButtons.push([buttonRect, this.pageUpFunction]);
        }

        if (this.page < maxPage){
            buttonRect = [rect[0] + rect[2] - 110, y, 100, 40];
            this.drawPanelButton(buttonRect, 'Page Down');
            panelButtons.push([buttonRect, this.pageDownFunction]);
        }
    }

    return panelButtons;
};


var allGoalPanelRender = function(rect, entity, ui){
    var panelButtons = [];
    var world = ui.world;

    var goals = _.filter(world.entities, function(worldEntity){
        return worldEntity.goalTrackComponent;
    });

    entity.absolutePositionComponent.size[1] = 200 + goals.length * 70;
    rect = entity.absolutePositionComponent.getAbsPosRect();

    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);

    ctx.fillStyle = this.textColor;
    ctx.font = getFont(28);
    ctx.fillText('Goals', rect[0] + 60, rect[1] + 60);

    ctx.font = getFont(20);
    _.each(goals, (goal, i) => {
        var y = rect[1] + 100 + (i + 1) * 70;
        ctx.drawImage(getImage(goal.clickComponent.image), rect[0] + 10, y - 35);
        
        ctx.fillStyle = this.textColor;
        ctx.fillText(goal.identityComponent.name, rect[0] + 80, y);

        var x = rect[0] + rect[2] - 100
        _.each(goal.uiActionComponent.getUiActions(goal, ui, entity), (fn, key) => {
            var buttonRect = [x, y - 25, 85, 30];
            x -= 100;
            this.drawPanelButton(buttonRect, key);
            panelButtons.push([buttonRect, fn]);
        });

        ctx.strokeStyle = this.insetColor;
        ctxRoundedRect([rect[0] + 5, y - 40, rect[2] - 10, 60]);
    });

    return panelButtons;
};


var allTrainPanelRender = function(rect, entity, ui){
    var panelButtons = [];
    var world = ui.world;
    
    var trainPaths = _.filter(world.entities, function(worldEntity){
        return worldEntity.trainPathComponent && 
            worldEntity.trainPathComponent.stoppable &&
            worldEntity.interactionComponent.canInteractSelf();
    });

    rect = entity.absolutePositionComponent.getAbsPosRect();

    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);

    ctx.fillStyle = this.textColor;
    ctx.font = getFont(28);
    ctx.textAlign = 'center';
    ctx.fillText('Trains of Thought', rect[0] + rect[2] / 2, rect[1] + 60);
    ctx.textAlign = 'left';

    ctx.font = getFont(20);
    ctx.fillStyle = this.textColor;
    ctx.strokeStyle = '#000000';

    for (var i = 0; i < 5; i++){
        var path = trainPaths[i];
        var y = rect[1] + 100 + (i + 1) * 80;
        
        if (path){
            var lastStop = world.entityForUid(_.last(path.trainPathComponent.trainStops));
            if (lastStop){
                lastStop.uiDataComponent.drawImage(lastStop, world, [rect[0] + 10, y - 36]);

                ctx.fillText(lastStop.identityComponent.name, rect[0] + 75, y);

                var buttonRect = [rect[0] + rect[2] - 60, y - 25, 40, 30];
                this.drawPanelButton(buttonRect, 'X');
                var cancelFunction = path.trainPathComponent.getKillTrainPath(path, world);
                panelButtons.push([buttonRect, cancelFunction]);
            }
        }
        else{
            ctx.textAlign = 'center';
            ctx.fillText('IDLE', rect[0] + rect[2] / 2, y);
        }

        ctxRoundedRect([rect[0] + 10, y - 40, rect[2] - 20, 60])
    };
    ctx.textAlign = 'left';

    return panelButtons;
};


var assertUnique = function(entity){
    console.log('Tried to make a duplicate of ' + entity.identityComponent.key);
    return false;
};


var autoPathGetReplaceKeys = function(entity, world){
    world.entityDeath();
    var paths = _.filter(world.entities, worldEntity => worldEntity.pathMoveComponent);
    var traits = _.filter(world.entities, worldEntity => worldEntity.mapSpawnComponent);
    for (var i = 0; i < traits.length; i++){
        console.log(i);
        var start = [traits[i].positionComponent.x, traits[i].positionComponent.y];
        for (var j = i + 1; j < traits.length; j++){
            console.log(j);
            var end = [traits[j].positionComponent.x, traits[j].positionComponent.y];
            world.ensurePath(start, end, paths);
        }
        break;
    }
    return false;
};


var autosaveOnGoalComplete = function(entity, args){
    var saveKey = 'save_' + args.key;
    adminConsole.save(saveKey);
};


var autosaveTick = function(entity, world){
    this.ticksToAutosave -= 1;
    if (this.ticksToAutosave > 0){
        return;
    }
    
    var chapter = _.filter(world.entities, function(worldEntity){
        return worldEntity.stageChangeComponent;
    })[0];

    if (chapter.identityComponent.key !== this.lastChapterKey){
        this.lastChapterKey = chapter.identityComponent.key;
        adminConsole.save(this.lastChapterKey);
    }

    adminConsole.save(PARAMETERS.autosaveKey);
    this.ticksToAutosave += (world.entities.length > 500) ? 3 : 1;
};


var checkEntityForBoost = function(entity){
    var that = this
    return entity.boostSocketComponent &&
        _.all(this.traits, function(trait){
            return _.contains(entity.boostSocketComponent.boostTraits, trait);
        });
};


var boostRender = function(rect, entity){
    ctx.drawImage(getImage('towerHex'), rect[0], rect[1]);
    ctx.fillStyle = '#ffff00';
    ctx.fillText(entity.identityComponent.name, rect[0] + rect[2] / 3, rect[1] + 2 * rect[3] / 3);
}


var makeExtraPathsExec = function(entity, world){
    world.makeExtraPaths([entity.positionComponent.x, entity.positionComponent.y]);
};


var buildingConnectExec = function(entity, world){
    if (PARAMETERS.buildingConnect){
        var stop;

        if (entity.identityComponent.sourceId){
            stop = world.entityForUid(entity.identityComponent.sourceId);
        }
        
        if (!stop && this.startEntityKey){
            stop = world.entityForKey(this.startEntityKey);
        }

        if (!stop || !stop.positionComponent){
            var baseKey = PARAMETERS.baseConnectKey ? PARAMETERS.baseConnectKey : PARAMETERS.self;
            stop = world.entityForKey(baseKey);
        }
        
        world.ensurePath(entity.positionComponent.getAsPos(), stop.positionComponent.getAsPos());
    }
};


var entityGenerateUiActions = function(entity, ui, panel){
    return {
        Inspect: function(){
            entity.clickComponent.onClick(entity, ui.world, ui);
            panel.panelComponent.closed = true;
        }
    };
};


var buildPanelRender = function(rect, entity, ui){
    entity.panelComponent.panelButtons = [];
    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);

    var size = 40;
    var y = rect[1] + rect[3] / 2 - size / 2;
    
    if (PARAMETERS.buildablePaths){
        if (!this.pathButtonFunction){
            this.pathButtonFunction = function(){
                ui.world.togglePathBuilding();
            };
        }

        
        var pathRect = [rect[0] + 30, y, size, size];
        this.drawImageButton(pathRect, 'pathButton')
        entity.panelComponent.panelButtons.push([pathRect, this.pathButtonFunction]);
        
        if (!this.demolishPathButtonFunction){
            this.demolishPathButtonFunction = function(){
                if (!ui.world.destroyPathMode){
                    ui.world.resetCurrents();
                    ui.world.destroyPathMode = true;
                }
                else{
                    ui.world.resetCurrents();
                }
            };
        }

        var demolishPathRect = [rect[0] + 100, y, size, size];
        this.drawImageButton(demolishPathRect, 'noPath');
        entity.panelComponent.panelButtons.push([demolishPathRect, this.demolishPathButtonFunction]);
    }

    if (!this.demolishButtonFunction){
        this.demolishButtonFunction = function(){
            if (!ui.world.destructionMode){
                ui.world.resetCurrents();
                ui.world.destructionMode = true;
            }
            else{
                ui.world.resetCurrents();
            }
        };
    }
        
    var demolishRect = [rect[0] + rect[3] / 2 - size / 2 + 20, y, size, size];
    this.drawImageButton(demolishRect, 'bulldozer');
    entity.panelComponent.panelButtons.push([demolishRect, this.demolishButtonFunction]);

    if (!this.settingsFunction){
        this.settingsFunction = function(){
            ui.world.openSettingsPanel();
        };
    };

    this.font = getFont(10);
    var settingsRect = [rect[0] + rect[2] - 50, rect[1] + rect[3] - 20, 50, 20];
    this.drawPanelButton(settingsRect, 'Options');
    entity.panelComponent.panelButtons.push([settingsRect, this.settingsFunction]);
};


var bulletTick = function(entity){
    entity.healthComponent.health = 0;
};


var bulletRender = function(rect, entity, ui){
    var startRect = ui.world.hexMap.cellForPosComp(this.bulletSourcePos).rect;
    var endRect = ui.world.hexMap.cellForPosComp(this.bulletEndPos).rect;
    ctx.strokeStyle = '#ffffff';
    ctx.beginPath();
    ctx.moveTo(startRect[0] + startRect[2] / 2, startRect[1] + startRect[3] / 2);
    var endPos = [endRect[0] + endRect[2] / 2, endRect[1] + endRect[3] / 2];
    ctx.lineTo(endPos[0], endPos[1]);
    ctx.stroke();
};


var renderButton = function(text, buttonRect, buttonFunction){
    ctx.drawImage(getImage('button_l'), buttonRect[0] - 4, buttonRect[1] - 1);
    ctx.drawImage(getImage('button_c'), buttonRect[0], buttonRect[1] - 1, buttonRect[2], buttonRect[3] + 6);
    ctx.drawImage(getImage('button_r'), buttonRect[0] + buttonRect[2], buttonRect[1] - 1);
    
    ctx.fillStyle = '#000000';
    ctx.fillText(text, buttonRect[0], buttonRect[1] + this.lineHeight - 2);
    this.panelButtons.push([buttonRect, buttonFunction]);
};


var buttonGenerateUiActions = function(entity, ui, panel){
    var managerKey = entity.buttonControlComponent.managerKey;
    var manager = ui.world.entityForKey(managerKey);

    var actions = {};

    if (manager){
        if (this.inspectFunction === undefined){
            this.inspectFunction = function(){
                ui.minimizeAllPanels();
                manager.clickComponent.onClick(manager, ui.world, ui);
            };
        }
        actions['Inspect'] = this.inspectFunction;

        if (entity.buttonControlComponent.canMakeEntity(ui.world)){
            actions['Build'] = entity.buttonControlComponent.getWrappedFunction(entity, ui.world, ui);
        }
    }
    
    return actions;
};


var carryTrainTick = function(entity, world){
    var currenciesHeld = entity.trainComponent.getCurrenciesHeld(entity, world);
    if (currenciesHeld.length === 0){
        entity.healthComponent.kill();
    }
};


var changeOpinion = function(entity, world){
    if (this.opinionToRemove){
        var opinions = _.isArray(this.opinionToRemove) ? this.opinionToRemove : [this.opinionToRemove];
        _.chain(opinions)
            .map(function(opinionKey){ return world.entitiesForKey(opinionKey); })
            .filter(function(opinion){
                return opinion.personHeldComponent.personHeld == entity.personHeldComponent.personHeld
            })
            .each(function(opinion){
                opinion.healthComponent.health = 0;
            });
    }
    
    if (this.opinionToAdd){
        world.makeEntities(entity, this.opinionToAdd);
    }
};


var chapterPanelRender = function(rect, entity, ui){
    var panelButtons = [];
    var gameStage = ui.world.getGameStage();

    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);

    ctx.fillStyle = this.textColor;
    ctx.font = (gameStage.identityComponent.name.length > 12) ? getFont(22) : getFont(28);
    drawCenteredText(gameStage.identityComponent.name, rect[0] + rect[2] / 2, rect[1] + 40);
    
    var x = rect[0] + 10;
    var y = rect[1] + 100;
    
    ctx.font = getFont(20);
    ctx.strokeStyle = '#000000';

    if (gameStage.dayResponseComponent.daysLeft > 0 && 
        Object.keys(gameStage.stageChangeComponent.goalsToCheck).length > 0){
        ctx.fillText('Days to go: ' + gameStage.dayResponseComponent.daysLeft, x, y);
        y += 40;
    }
    
    _.each(gameStage.stageChangeComponent.goalsToCheck, (chk, goalKey) => {
        if (allArgs[goalKey]){
            ctx.strokeRect(x, y - 14, 14, 14);

            if (chk <= 0){
                ctx.drawImage(getImage("tick"), x, y - 16);
            }
            else if (this.canShowGoal(goalKey, ui.world)){
                var buttonRect = [rect[0] + rect[2] - 110, y - 18, 100, 25];
                this.drawPanelButton(buttonRect, 'GO');
                
                if (!this.goalOpenFunctions[goalKey]){
                    this.goalOpenFunctions[goalKey] = (entity, ui) => {
                        this.showGoal(goalKey, ui.world, entity, ui);
                    };
                }

                panelButtons.push([buttonRect, this.goalOpenFunctions[goalKey]]);
            }

            txt = allArgs[goalKey].name;

            ctx.fillText(txt, x + 30, y);
            
            y += 30;
        }
    });
     
    return panelButtons;
};

var chapterPanelCanShowGoal = function(goalKey, world){
    return world.entityForKey(goalKey) ||
        _.any(world.entities, worldEntity => (worldEntity.buttonControlComponent && 
                                              worldEntity.buttonControlComponent.entityKey == goalKey));
};

var chapterPanelShowGoal = function(goalKey, world, entity, ui){
    entityPanelClose(entity, ui);
    
    var goal = world.entityForKey(goalKey);
    if (goal){
        goal.clickComponent.onClick(goal, world, ui);
    }
    else{
        var button = _.filter(world.entities, worldEntity => (worldEntity.buttonControlComponent && 
                                                              worldEntity.buttonControlComponent.entityKey == goalKey))[0];
        if (button){
            var manager = world.entityForKey(button.buttonControlComponent.managerKey);
            if (manager){
                manager.clickComponent.onClick(manager, world, ui);
            }
        }
    }
};


var checkManagedComponent = function(entity, world){
    if (entity.managedComponent){
        var manager = world.entityForKey(entity.managedComponent.managerKey);
        if (!manager){
            entity.healthComponent.kill();
        }
    }
};


var checkQualityTick = function(entity, world){
    var qualityEntity = world.entityForKey(this.qualityKey);
    if (qualityEntity && qualityEntity.qualityComponent.quality < this.minQuality){
        world.makeEntities(entity, this.minQualityEntities);
    }
};


var clearTraitExec = function(entity, world){
    _.each(world.entities, worldEntity => {
        if (worldEntity.managedComponent && worldEntity.managedComponent.managerKey == this.trait){
            worldEntity.healthComponent.kill();
        }
    });
};


var clickTextRender = function(rect, entity){
    ctx.fillStyle = '#ff00ff';
    ctx.fillText(entity.identityComponent.name, rect[0], rect[1] + rect[3] / 4);
};


var clickKill = function(entity){
    entity.healthComponent.health = 0;
};


var closestOpenPositionExec = function(entity, world){
    var checkedPositions = [];
    var positionsToCheck = [this.startPos];
    for (var j = 0; j < 10; j++){
        var nextPositions = [];
        for (var i = 0; i < positionsToCheck.length; i++){
            var checkPos = positionsToCheck[i];
            if (world.isPosBuildable(checkPos) && (
                checkPos[0] > 1 && 
                    checkPos[1] > 1 && 
                    checkPos[0] < PARAMETERS.size[0] - 1 &&
                    checkPos[1] < PARAMETERS.size[1] - 1
            )){
                entity.positionComponent.x = checkPos[0];
                entity.positionComponent.y = checkPos[1];
                return;
            }
            else{
                checkedPositions.push(checkPos);
                _.each(world.hexMap.neighbors(checkPos[0], checkPos[1]), function(neighbor){
                    if (!_.any(checkedPositions, function(checkedPos){ return comparePos(checkedPos, neighbor); })){
                        nextPositions.push(neighbor);
                    }
                });
            }
        }
        positionsToCheck = nextPositions;
    }
    
    if (entity.healthComponent){
        entity.healthComponent.kill();
    }
};


var conditionalMakeGetReplaceKeys = function(entity, world){
    if (_.any(this.stopEntities, function(stopEntityKey){ return world.entityForKey(stopEntityKey); })){
        return false;
    }
    return this.entitiesToMake;
};


var connectSourceGetReplaceKeys = function(entity, world){
    var source = world.entityForUid(this.sourceId);
    
    if (!source){
        return;
    }
    
    var source2 = world.entityForUid(source.identityComponent.sourceId);

    world.connectEntities(source, source2);
};


var construct = function(entity, world){
    world.makeEntities(entity, this.constructionIdentifier, {
        constructed: true
    });
    
    world.addEntity(makeEcs(PARAMETERS.notification, {
        notificationKey: PARAMETERS.goalComplete,
        notificationArgs: {
            key: entity.identityComponent.key
        }
    }));
};


var constructionRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    if (this.timeDrawn < 2){
        this.timeDrawn += lastInterval;
    }

    var img = getImage(this.image);
    
    if (this.timeDrawn < 0.05){
        return;
    }
    else if (this.timeDrawn < this.scaleTime){
        var scale = 1 + 0.5 * (this.scaleTime - this.timeDrawn) / this.scaleTime;
        scaledDraw(img, rect, scale);
    }
    else{
        var x = rect[0] + this.getWobble(lastInterval);
        ctx.drawImage(img, x, rect[1]);

        ctx.fillStyle = '#ffffff';
        ctx.fillRect(rect[0] + 17, rect[1] + 32, 26, 17);
        ctx.drawImage(getImage('construction'), rect[0] + 17, rect[1] + 32);
        
        if (this.outlineImage){
            ctx.drawImage(getImage(this.outlineImage), x, rect[1]);
            this.outlineImage = false;

            this.renderTrainIcon(lastInterval, x, rect[1]);
        }
    }

    if (this.timeDrawn > this.scaleTime && this.timeDrawn < this.scaleTime * 1.5){
        var dustImage = getImage(this.dustImage);
        var dist = ((this.timeDrawn - this.scaleTime) / (3 * this.scaleTime)) + 1;
        for (var i = 0; i < 5; i++){
            var angle = 2 * Math.PI * i / 5;
            var x = 60 * dist * Math.cos(angle);
            var y = 60 * dist * Math.sin(angle);
            ctx.drawImage(dustImage, rect[0] + rect[2] / 2 + x, rect[1] + rect[3] / 2 + y);
        }
    }
};


var constructionGetCurrencyComponent = function(entity){
    return entity.constructionComponent;
}


var constructOnClick = function(entity, world, ui){
    var uiKey = '#' + entity.identityComponent.key + '_' + entity.uid;
    ui.openPanelAtPos(uiKey, entity.positionComponent);
};


var constructionTick = function(entity, world){
    entity.constructionComponent.ticked = true;
};


var constructionMenuCloseExec = function(entity, world){
    if  (!entity.constructionComponent.ticked &&
         !_.any(world.entities, function(worldEntity){
             return worldEntity.trainPathComponent &&
                 _.contains(worldEntity.trainPathComponent.trainStops, entity.uid);
         })
        ){
        entity.healthComponent.kill();
    }
};


var getWrappedFunction = function(entity, world, ui){
    if (!this.wrappedFunction){
        this.wrappedFunction = function(){
            world.resetCurrents();
            if (entity.buttonControlComponent.canMakeEntity(world)){
                world.currentMakingEntity = entity;
                ui.minimizeAllPanels();
            }
        }
    }

    return this.wrappedFunction;
};

var controlComponentGetAiVal = function(world){
    return this.aiVal;
};


var controlPanelHandleKeyPress = function(key, entity, ui){
    if (key == 48 || key == 32 || key == 112){
        ui.pause();
    }
    else if (key == 81){
        entity.panelTrackComponent.closeTrackedPanel(ui);
    }
    else if (key == 80 && PARAMETERS.buildablePaths){
        ui.world.togglePathBuilding();
    }
    else if (key == 27){
        if (!entity.panelTrackComponent.closeTrackedPanel(ui)){
            ui.world.openSettingsPanel();
        }
    }
    else if (key > 48 && (key - 48 <= PARAMETERS.ticksPerTick.length)){
        ui.setSpeed(PARAMETERS.ticksPerTick[key - 49]);
    }

    var panelDict = {
    };
    var panelKey = panelDict[key];
    if (panelKey !== undefined){
        var infoPanel = ui.getPanel(panelKey);
        flipPanel(infoPanel, ui);
    }
};


var trackPanels = function(entities){
    var that = this;
    var panelKeysToRemove = [];
    var panelKeysToAdd = [];

    _.chain(entities)
        .filter(function(entity){
            return entity.panelComponent && entity.panelComponent.canClose;
        })
        .each(function(entity){
            var key = entity.identityComponent.key;
            if (entity.panelComponent.closed && _.contains(that.panelsOpened, key)){
                panelKeysToRemove.push(key);
            }
            else if (!entity.panelComponent.closed && !_.contains(that.panelsOpened, key)){
                panelKeysToAdd.push(key);
            }
        });
    
    this.panelsOpened = _.difference(this.panelsOpened, panelKeysToRemove).concat(panelKeysToAdd);
};

var closeTrackedPanel = function(ui){
    var world = ui.world;
    if (this.panelsOpened.length > 0){
        var panel = world.entityForKey(_.last(this.panelsOpened));
        if (panel){
            entityPanelClose(panel, ui);
        }
        this.panelsOpened.splice(this.panelsOpened.length - 1, 1);
        return true;
    }
    return false;
};

var closeAllPanels = function(ui){
    var world = ui.world;
    _.each(this.panelsOpened, function(panel){
        var panelToClose = world.entityForKey(panel);
        if (panelToClose){
            entityPanelClose(panelToClose, ui);
        }
    });
    this.panelsOpened = [];
};


var creepTick = function(entity, world){
    _.each(entity.rendererComponents, function(renderComponent){
        if (renderComponent.activated){
            renderComponent.activated -= 1;
        }
    });
};


var creepCreateExec = function(entity, world){
    if (this.makeTrain){
        var source = world.entityForUid(this.sourceId);
        var source2 = world.entityForKey(source.managedComponent.managerKey);

        if (!source2){
            entity.healthComponent.kill();
            return;
        }

        var self = world.entityForKey(this.destination);

        if (this.firstTick){
            var paths = world.getAllPaths();
            world.ensurePath([source2.positionComponent.x, source2.positionComponent.y],
                             [entity.positionComponent.x, entity.positionComponent.y],
                             paths);
            
            world.ensurePath([source2.positionComponent.x, source2.positionComponent.y],
                             [self.positionComponent.x, self.positionComponent.y],
                             paths);
        }
                
        var trainPath = makeEcs(this.creepTrainPath, {
            trainStops: [self.uid],
            trainStartId: entity.uid,
            focusCost: 0
        });
        world.addEntity(trainPath);
    }
};


var creepDeathExec = function(entity, world){
    var creepDeath = makeEcs(this.creepDeathKey, {
        renderPos: entity.rendererComponents[0].renderPos,
        image: entity.rendererComponents[0].image
    });
    world.addEntity(creepDeath);
};


var creepDeathRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    if (this.timeLeft < 0.25 || this.renderPos === undefined){
        entity.healthComponent.kill();
    }
    else{
        var width = this.timeLeft * this.size[0];
        var height = this.timeLeft * this.size[1];
        ctx.drawImage(getImage(this.image), 
                      this.renderPos[0] + this.size[0] / 2 - width / 2,
                      this.renderPos[1] + this.size[1] / 2 - height / 2,
                      width, height);
        this.timeLeft -= lastInterval;
    }
};


var getImmediateEmotionRect = function(rect, entity, rectCount){
    var size = 20;
    var x = rect[0] + rect[2] / 2 - size / 2;
    var y = rect[1] + rect[3] / 2 - size / 2;
    

    return [x, y, size, size];
};

var getEmotionRect = function(rect, entity, rectCount, ui){
    var emotionRect = getImmediateEmotionRect(rect, entity, rectCount);
    
    var ticks = ui.world.game.tickSystemWrapper.ticks;

    if (entity.pathVelocityComponent.isMoving){
        var fraction;
        var movingIndex = Math.floor(ticks / 5);
        if (entity.pathVelocityComponent.moveIndex < movingIndex){
            fraction = 1;
        }
        else if (entity.pathVelocityComponent.moveIndex > movingIndex){
            fraction = 0;
        }
        else{
            ticks = ticks % 5;
            fraction = ticks / 5;
        }
        
        var nextPos = entity.pathVelocityComponent.chosenPath[0];
        var nextRect = ui.world.hexMap.cellForPosComp({ x: nextPos[0], y: nextPos[1]}).rect;
        
        var interpolatedPos = [
            rect[0] + (nextRect[0] - rect[0]) * fraction + (rect[2] / 2) - emotionRect[2] / 2,
            rect[1] + (nextRect[1] - rect[1]) * fraction + (rect[3] / 2) - emotionRect[3] / 2,
        ];
        return [interpolatedPos[0], interpolatedPos[1], emotionRect[2], emotionRect[3]];
    }

    return emotionRect;
};

var currencyRender = function(rect, entity, ui, rectCount){
    var renderPos = this.renderPos;
    if (renderPos){
        ctx.drawImage(getImage(this.image), renderPos[0], renderPos[1]);
        ctx.fillStyle = '#ffffff';
        ctx.fillText(entity.identityComponent.name, renderPos[0], renderPos[1]);
    }
    else{
        var currencyRenderEntity = ui.world.entityForKey(PARAMETERS.currencyRenderEntity);
        currencyRenderEntity.currencyRenderEntityComponent.addCurrencyToRender([entity.positionComponent.x, 
                                                                                entity.positionComponent.y],
                                                                               this.image,
                                                                               entity.identityComponent.name);
    }
};


var currencyDayEnd = function(entity, world){
    var heldIds = _.chain(world.entities)
        .filter(function(worldEntity){
            return worldEntity.carriageComponent;
        })
        .map(function(carriage){
            return carriage.carriageComponent.holding;
        })
        .flatten(true)
        .value();

    if (!_.contains(heldIds, entity.uid)){
        entity.healthComponent.kill();
    }
};


var addCurrencyToRender = function(pos, image, name){
    var record = _.chain(this.currenciesToRender)
        .filter(function(chkRecord){
            return chkRecord.x == pos[0] &&
                chkRecord.y == pos[1] &&
                chkRecord.image == image &&
                chkRecord.name == name;
        })
        .first()
        .value();

    if (record){
        record.count += 1;
    }
    else{
        this.currenciesToRender.push({
            x: pos[0],
            y: pos[1], 
            image: image, 
            name: name, 
            count: 1});
    }
};


var allCurrencyRenderClear = function(rect, entity){
    entity.currencyRenderEntityComponent.currenciesToRender = [];
};


var allCurrencyRender = function(rect, entity, ui){
    var size = 20;
    ctx.fillStyle = '#ffffff';
    _.each(entity.currencyRenderEntityComponent.currenciesToRender, function(record){
        var renderRect = ui.world.hexMap.cellForPosComp(record).rect;
        var x = renderRect[0] + renderRect[2] / 2 - size / 2;
        var y = renderRect[1] + renderRect[3] / 2 - size / 2 + 5;

        for (var i = 0; i < record.count; i++){
            ctx.drawImage(getImage(record.image), x, y + i * 4);
        }
        var txt = record.name;
        ctx.fillText(txt, x, y);
    });
};


var currencyRequestedCurrenciesNeededAtPoint = function(entity){
    var currencyComponent = this.getCurrencyComponent(entity);
    return _.chain(currencyComponent.currencyRequested)
        .keys()
        .filter(function(key){
            return currencyComponent.currencyRequested[key] > 0;
        })
        .value();
};

var currencyRequestedInteractWithTrain = function(entity, world, train){
    var carriage = train.trainComponent.getCurrentCarriage(train, world);
    var didInteract = false;
    var currencyComponent = this.getCurrencyComponent(entity);

    _.chain(carriage.carriageComponent.holding)
        .map(holdingId => world.entityForUid(holdingId))
        .filter(holding => holding && holding.identityComponent)
        .each(function(holding){
            didInteract = true;
            var holdingKey = holding.identityComponent.key;
            holding.healthComponent.kill();
            if (currencyComponent.currencyRequested[holdingKey] > 0){
                currencyComponent.currencyRequested[holdingKey] -= 1;
            }
        });
    
    if (didInteract){
        if (this.currencyEntities){
            world.makeEntities(entity, this.currencyEntities);
        }

        if (this.currencyEffect){
            var rect =  world.hexMap.cellForPosComp(entity.positionComponent).rect;
            world.makeEntities(entity, this.currencyEffect, {
                effectPos: [rect[0] + rect[2] / 2, rect[1] + rect[3] / 2]
            });
        }
    }

    if (_.all(currencyComponent.currencyRequested, function(val){ return val == 0; })){
        var trainPath = world.entityForUid(train.trainVelocityComponent.trainPath);
        
        if (trainPath){
            if (entity.uiDataComponent){
                var stops = _.map(trainPath.trainPathComponent.trainStops, function(stopId){
                    return world.entityForUid(stopId);
                });

                if (_.all(stops, _.identity)){
                    var path = _.map(stops, function(stop){
                        var traitImage = stop.managedComponent ? 
                            traitImageForKey(stop.managedComponent.managerKey, world) : 
                            undefined;
                        return {
                            name: stop.identityComponent.name,
                            traitImage: traitImage,
                            image: stop.uiDataComponent.image
                        };
                    });
                    
                    entity.uiDataComponent.lastPath = path;
                }
            }

            trainPath.healthComponent.kill();
        }
        train.healthComponent.kill();
    }
    
    return false;
};

var currencyRequestedFocusPathStopPercentComplete = function(entity){
    var comp = this.getCurrencyComponent(entity);
    var currencyLeft = _.reduce(comp.currencyRequested, addFunction, 0);
    var allCurrency = _.reduce(comp.origCurrencyRequested, addFunction, 0);
    return Math.round((1 - (currencyLeft / allCurrency)) * 100);
};


var cursorRender = function(rect, entity, ui){
    var mousePos = ui.game.lastPos;
    var image;
    var button = ui.world.currentMakingEntity;
    if (button){
        var trait = ui.world.entityForKey(button.buttonControlComponent.managerKey);
        if (trait){
            ctx.drawImage(getImage(trait.uiDataComponent.image), mousePos[0] - 30, mousePos[1] - 26);
        }
        image = getImage(button.uiDataComponent.image);
        ctx.drawImage(image, mousePos[0] - 30, mousePos[1] - 26);
    }
    else if (ui.world.currentPath){
        ctx.strokeStyle = '#0099ff';
        ctx.beginPath();
        ctx.moveTo(mousePos[0], mousePos[1] - 10);
        ctx.lineTo(mousePos[0], mousePos[1] + 10);
        ctx.stroke();
    }
    else if (ui.world.destructionMode || ui.world.destroyPathMode){
        image = getImage('demolishIcon');
        ctx.drawImage(image, mousePos[0] - 16, mousePos[1] - 16);
    }
};


var dailyEntityMake = function(entity, world){
    var comp = entity.dailyEntityMakerComponent;
    comp.dayCount -= 1;
    if (comp.dayCount <= 0){
        var neighbors = world.hexMap.neighbors(entity.positionComponent.x, entity.positionComponent.y);
        var pos = _.chain(neighbors)
            .filter(function(neighbor){
                return world.isPosBuildable(neighbor);
            })
            .sample()
            .value();

        if (!pos){
            return;
        }

        world.makeEntities(entity, comp.dayStartEntity, {
            x: pos[0],
            y: pos[1]
        });
        
        comp.dayCount = comp.daysToMake;
    }
};


var getAllEmotionParts = function(){
    return [this.emotion].concat(this.traits);
}


var checkTargetEntity = function(targetEntity, entity, world){
    var entityCheck = (targetEntity !== entity &&
                       targetEntity.identityComponent !== undefined &&
                       targetEntity.positionComponent !== undefined &&
                       targetEntity.healthComponent !== undefined &&
                       targetEntity.healthComponent.health > 0 &&
                       targetEntity.damageableComponent !== undefined);
    if (!entityCheck){
        return false;
    }
    
    var damage = this.calculateDamage(targetEntity);
    if (damage === 0){
        return false;
    }

    var targetPos = [targetEntity.positionComponent.x, targetEntity.positionComponent.y];

    var hitPos = this.getHitPos(entity, world);

    return _.any(hitPos, function(neighbor){ return _.isEqual(neighbor, targetPos); });
};

var getHitPos = function(entity, world){
    if (!this.hitPos){
        var neighbors = world.hexMap.neighbors(entity.positionComponent.x, entity.positionComponent.y);
        this.hitPos = neighbors.concat([entity.positionComponent.x, entity.positionComponent.y]);
    }
    return this.hitPos;
};

var calculateDamage = function(targetEntity){
    var relevantTraits = _.filter(targetEntity.damageableComponent.getAll(), (key) => { 
        return this.damageMultipliers[key] !== undefined; 
    });
    
    if (relevantTraits.length === 0){
        return 0;
    }

    var multiplier = _.chain(relevantTraits)
            .map((key) => { return this.damageMultipliers[key]; })
            .reduce(addFunction, 0)
            .value();

    return this.damage * multiplier;
};


var damageIndicatorRender = function(rect, entity, ui){
    var source = ui.world.entityForUid(self.sourceId);
    
    if (source){
        rect = ui.world.hexMap.cellForPosComp(source.positionComponent).rect;
        ctx.fillStyle = '#000000';
        ctx.fillRect(rect[0] + 20, rect[1] + 20, 20, 20);
    }
};


var damamgeUpgradeCheckExec = function(entity, world){
    var existingUpgrades =_.filter(world.entities, (worldEntity) => {
        return worldEntity.damageUpgradeComponent &&
            _.contains(worldEntity.damageUpgradeComponent.towerKeys, this.towerKey);
    });
    
    if (existingUpgrades.length >= this.maxUpgradeCount - 1){
        _.each(this.entitiesToKill, function(entityKey){
            _.each(world.entitiesForKey(entityKey), function(worldEntity){
                worldEntity.healthComponent.kill();
            });
        });

        world.flags[this.flag] = true;
    }
};


var getPartOfDay = function(){
    var partsOfDay = ['early morning', 'late morning', 'afternoon', 'evening', 'night'];
    var index = Math.floor((this.impulseTicks - this.ticks) / (this.impulseTicks / partsOfDay.length));
    return partsOfDay[index];
};


var dayKillExec = function(entity, world){
    world.makeEntities(entity, PARAMETERS.day, {
        dayCount: entity.dayCounterComponent.dayCount + 1
    });
    adminConsole.save('day');
};


var drawBar = function(rect, fraction){
    ctx.fillStyle = '#000000';
    ctxFillRect(rect);

    rect[2] *= fraction;
    ctx.fillStyle = '#ffffff';
    ctxFillRect(rect);
};

var dayPanelRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    entity.panelComponent.panelButtons = [];
    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);
    ctx.fillStyle = this.textColor;
        
    if (ui.world.isEntityPaused()){
        var pausingEntity = findPausingEntity(ui);
        this.flashTimer += lastInterval;
        if (this.flashTimer < 1.8){
            if (pausingEntity){
                var showPauseRect = [rect[0] + rect[2] / 2 - 100, rect[1] + rect[3] / 2 - 25, 200, 50];
                this.textColor = '#ffd700';
                this.insetColor = '#ffd700'
                this.drawPanelButton(showPauseRect, 'SHOW NEW GOAL');
                this.textColor = '#000000';
                this.insetColor = '#000000';
                entity.panelComponent.panelButtons.push([showPauseRect, this.showPausingEntity]);
            }
            else{
                ctx.font = getFont(30);
                drawCenteredText('PAUSED', rect[0] + rect[2] / 2, rect[1] + rect[3] / 2 + 15);
                ctx.font = BASE_FONT;
            }
        }
        else if (this.flashTimer > 2){
            this.flashTimer -= 2;
        }
    }
    else{
        var gameStage = ui.world.getGameStage();
                
        if (gameStage){
            if (this.displayGameStage === undefined){
                this.displayGameStage = function(){
                    var chapterMenu = ui.world.entityForKey(PARAMETERS.chapterPanel);
                    if (!chapterMenu){
                        chapterMenu = makeEcs(PARAMETERS.chapterPanel);
                        ui.world.addEntity(chapterMenu);
                    }
                    chapterMenu.panelComponent.expandPanel();
                };
            }

            var buttonRect = [rect[0] + rect[2] / 2 - 95, rect[1] + 10, 190, 30];
            this.drawPanelButton(buttonRect, gameStage.identityComponent.name);
            entity.panelComponent.panelButtons.push([buttonRect, this.displayGameStage]);
        }

        var day = _.chain(ui.world.entities)
            .filter(function(worldEntity){
                return worldEntity.dayCounterComponent;
            })
            .first()
            .value();

        if (day){
            ctx.fillText('Day ' + day.dayCounterComponent.dayCount, rect[0] + rect[2] / 2 - 95, rect[1] + rect[3] - 30);
            drawBar([rect[0] + rect[2] / 2 - 47, rect[1] + rect[3] - 38, 135, 5], 
                    1 - (day.dayCounterComponent.ticks / day.dayCounterComponent.impulseTicks));

            var dayActions;
            if (this.dayActions){
                dayActions = this.dayActions;
            }
            else{
                dayActions = [['[P]ause', ui.pause]];

                _.each(PARAMETERS.ticksPerTick, function(ticksPerTick){
                    txt = '[' + Math.floor(ticksPerTick / PARAMETERS.ticksPerTick[0]) + ']x';
                    dayActions.push([txt, function(){ ui.setSpeed(ticksPerTick); }]);
                });
                this.dayActions = dayActions;
            }

            var ticksPerTick = PARAMETERS.ticksPerTick;
            var currentIdx = ui.game.tickSystemWrapper.running ? 
                (ticksPerTick.indexOf(ui.game.ticksPerTick) + 1) : 
                0;

            _.each(dayActions, (data, i) => {
                var text = data[0];
                var fn =  data[1];
                var actionRect = [rect[0] + rect[2] / 2 - 87 + 60 * i, rect[1] + rect[3] - 22, 55, 20];
                this.drawPanelButton(actionRect, text);

                if (currentIdx == i){
                    ctx.strokeStyle = '#ff0000';
                    ctx.strokeRect(actionRect[0], actionRect[1], actionRect[2], actionRect[3]);
                }

                entity.panelComponent.panelButtons.push([actionRect, fn]);
            });

            
        }

        var pointCounter = _.filter(ui.world.entities, function(worldEntity){
            return worldEntity.pointCounterComponent;
        })[0];
    }
};

var showPausingEntity = function(entity, ui){
    var pausingEntity = findPausingEntity(ui);
    if (pausingEntity){
        pausingEntity.clickComponent.onClick(pausingEntity, ui.world, ui);
    }
};

var findPausingEntity = function(ui){
    return _.chain(ui.world.entities)
        .filter((worldEntity) => worldEntity.pauseComponent && worldEntity.pauseComponent.paused && worldEntity.clickComponent)
        .first()
        .value();
};


var demolishButtonRender = function(rect, entity, ui){
    if (!this.demolishButtonFunction){
        this.demolishButtonFunction = function(){
            if (!ui.world.destructionMode){
                ui.world.resetCurrents();
                ui.world.destructionMode = true;
            }
            else{
                ui.world.resetCurrents();
            }
        };
    }
    ui.informLine(PARAMETERS.buildPanel, {
        buttonFunction: this.demolishButtonFunction,
        text: 'demolish'
    }, PARAMETERS.baseButtonName);
};


var demolishPathButtonRender = function(rect, entity, ui){
    if (!this.demolishPathButtonFunction){
        this.demolishPathButtonFunction = function(){
            if (!ui.world.destroyPathMode){
                ui.world.resetCurrents();
                ui.world.destroyPathMode = true;
            }
            else{
                ui.world.resetCurrents();
            }
        };
    }

    ui.informLine(PARAMETERS.buildPanel, {
        buttonFunction: this.demolishPathButtonFunction,
        text: 'remove path'
    }, PARAMETERS.baseButtonName);
};


var depositInteractWithTrain = function(entity, world, train){
    var trainRequirements = train.trainComponent.calculateTrainCurrencies(train, world);

    var deposit = entity.depositComponent.deposit;
    
    for (var key in deposit){
        if (deposit[key] > 0 && trainRequirements[key] > 0){
            var currency = world.makeEntities(entity, key)[0];
            var carriage = train.trainComponent.getCurrentCarriage(train, world);
            carriage.carriageComponent.holding.push(currency.uid);

            deposit[key] -= 1;
        }
    }
    
    return false;
};

var depositCurrenciesMadeAtPoint = function(entity){
    return _.chain(entity.depositComponent.deposit)
        .map(function(val, key){
            return (val > 0) ? key : false;
        })
        .filter(_.identity)
        .value();
};


var depositTick = function(entity, world){
    if (_.all(entity.depositComponent.deposit, function(val){ return val == 0; })){
        entity.healthComponent.health = 0;
    }
};


var checkMakeDeposit = function(entity, world){
    if (this.checkMakeDeposit){
        var existingDeposit = _.chain(world.entities)
            .filter(function(worldEntity){
                return worldEntity.depositComponent &&
                    _.all(entity.depositComponent.deposit, function(val, key){
                        return worldEntity.depositComponent.deposit[key];
                    }) &&
                    ((!entity.managedComponent && !worldEntity.managedComponent) ||
                     (entity.managedComponent && worldEntity.managedComponent &&
                      entity.managedComponent.managerKey == worldEntity.managedComponent.managerKey))
            })
            .first()
            .value();
            
        if (existingDeposit){
            addDict(existingDeposit.depositComponent.deposit, entity.depositComponent.deposit);
            entity.healthComponent.kill();
            if (existingDeposit.timedDeathComponent && entity.timedDeathComponent){
                existingDeposit.timedDeathComponent.timeToDeath = entity.timedDeathComponent.timeToDeath;
            }
        }
    }
};


var depositPositionExec = function(entity, world){
    if (this.randomPosition ||
        entity.positionComponent.x === undefined ||
        entity.positionComponent.y === undefined ||
        entity.managedComponent === undefined){
        randomOpenPositionExec(entity, world);
    }
}


var disabledTowerRender = function(rect, entity){
    ctx.drawImage(getImage(this.image), rect[0], rect[1]);
    ctx.fillStyle = '#ffffff';
    ctx.fillText(entity.identityComponent.name, rect[0] + rect[2] / 2, rect[1] + 3 * rect[3] / 4);
};


var checkMemoriesDisabled = function(trait){
    return trait && trait.memoryComponent;
};


var disableMemoriesTick = function(entity, world){
    var timeLeft = Math.floor(entity.timedDeathComponent.timeToDeath / PARAMETERS.ticksPerTick[0]);
    entity.identityComponent.name = this.name + ' (' + timeLeft + ')';
};


var checkTraitDisabled = function(trait){
    return trait && _.contains(this.traitsToDisable, trait.identityComponent.key);
};


var emotionResourceDifficultyExec = function(entity, world){
    var difficulty = world.entityForKey(PARAMETERS.difficultySetting).difficultySettingComponent.difficulty;
    entity.resourceComponent.resourceCount = max(entity.resourceComponent.resourceCount - difficulty, 1);
};


var emotionSourceCreateExec = function(entity, world){
    var spawnSource = world.entityForKey(this.sourceKey);

    if (!spawnSource){
        console.log('Failed to make emotion source because source key missing - ' + this.sourceKey);
        return;
    }

    if (!spawnSource.positionComponent){
        console.log(this.sourceKey + ' is missing a position component, so cannot spawn emotion source.')
    }
    
    var memory = world.entityForKey(this.memoryKey);
    var paths = world.getAllPaths();

    if (memory){
        if (memory.entityManagerComponent.disabled){
            return;
        }
        
        memory.healthComponent.health += 100;

        var space = memory.entityManagerComponent.findFreeManagedSpace(memory, world);

        if (space){
            world.makeEntities(memory, this.resourceKey, {
                x: space.positionComponent.x,
                y: space.positionComponent.y,
                sourceTrait: this.memoryKey
            });

            world.ensurePath([memory.positionComponent.x, memory.positionComponent.y],
                             [space.positionComponent.x, space.positionComponent.y],
                             paths);
        }
    }
    else{
        if (_.any(world.entities, worldEntity => (worldEntity.disableTraitComponent && 
                                                  worldEntity.disableTraitComponent.disableNewMemories))){
            return;
        }
        
        var emotion = allArgs[this.memoryKey].memoryEmotions[0];
        
        var startManagedEntities = _.chain(world.entities)
            .filter(function(worldEntity){
                return worldEntity.emotionResourceMapComponent &&
                    worldEntity.emotionResourceMapComponent.emotionToMap == emotion;
            })
            .map(function(worldEntity){
                return worldEntity.emotionResourceMapComponent.startManagedEntities;
            })
            .flatten(true)
            .value();
        startManagedEntities.push(this.resourceKey)

        memory = world.makeEntities(entity, this.memoryKey, {
            source2Key: this.sourceKey,
            sourceName: spawnSource.identityComponent.name,
            startManagedEntities: startManagedEntities,
            startPos: [spawnSource.positionComponent.x, spawnSource.positionComponent.y]
        })[0];

        var shouldKill = true;
        if (memory && memory.healthComponent.health > 0){
            shouldKill = world.ensurePath([memory.positionComponent.x, memory.positionComponent.y],
                                          [spawnSource.positionComponent.x, spawnSource.positionComponent.y],
                                          paths) === undefined;
        }
        
        if (shouldKill){
            entity.healthComponent.kill();
        }
    }
};


var emotionSourceConstructionCreateExec = function(entity, world){
    var memory = world.entityForKey(this.sourceKey);
    var source = world.entityForKey(memory.memoryComponent.source2Key);
    
    if (source){
        var focusStop = world.makeEntities(source, this.focusStopKey)[0];
        
        var trainPath = world.makeEntities(entity, this.trainPath, {
            trainStops: [entity.uid],
            trainStartId: focusStop.uid
        })[0];

        world.ensurePath([entity.positionComponent.x, entity.positionComponent.y],
                         [memory.positionComponent.x, memory.positionComponent.y],
                         world.getAllPaths());
    }
    else{
        entity.healthComponent.kill();
    }
};


var endGoalExecute = function(entity, world){
    world.flags[this.flag] = true;
    _.each(world.entitiesForKey(this.buttonKey), entity => entity.healthComponent.kill());
};


var makeLifecycleEntities = function(entity, world, entitiesToMake){
    this.entitiesMade = _.map(world.makeEntities(entity, entitiesToMake), function(entity){
        return entity.uid;
    });
};

var endLifecycle = function(world){
    _.each(this.entitiesMade, function(entityUid){
        var entity = world.entityForUid(entityUid);
        if (entity){
            entity.healthComponent.kill();
        }
    });
};


var canMakeManagedEntity = function(entity, world){
    return true;
};

var findFreeManagedSpace = function(entity, world){
    var key = entity.identityComponent.key;

    var managedEntities = _.filter(world.entities, function(worldEntity){
        return worldEntity.managedComponent &&
            worldEntity.managedComponent.managerKey == key;
    });

    var space = _.chain(world.entities)
        .filter(function(worldEntity){
            return (worldEntity.identityComponent && worldEntity.identityComponent.key == key) ||
                (worldEntity.sourceExtensionComponent && worldEntity.sourceExtensionComponent.sourceKey == key);
        })
        .filter(function(worldEntity){
            return !_.any(managedEntities, function(managedEntity){
                return managedEntity.positionComponent.comparePos(worldEntity.positionComponent);
            });
        })
        .sample()
        .value();
    
    return space;
};

var checkForNewManaged = function(entity, world){
    this.hasNew = _.any(world.entities, worldEntity => (worldEntity.buttonControlComponent &&
                                                        worldEntity.buttonControlComponent.isNew &&
                                                        worldEntity.buttonControlComponent.managerKey == entity.identityComponent.key));
};


var getSaneName = function(entityKey){
    if (allArgs[entityKey]){
        return allArgs[entityKey].name;
    }
    else{
        return entityKey;
    }
};

var sanitize = function(entityKeys){
    if (_.isArray(entityKeys)){
        return reduceArray(_.map(entityKeys, getSaneName));
    }
    else if (_.isObject(entityKeys)){
        return _.reduce(entityKeys, function(memo, val, key){
            var st = sanitize(key) + ' (' + val + ')';
            return memo ? (memo + ', ' + st) : st;
        }, false);
    }
    else{
        return getSaneName(entityKeys);
    }
};

var entityPanelRender = function(rect, entity, ui){
    var panelButtons = [];
    var world = ui.world;
    var building = world.entityForUid(entity.panelComponent.sourceId);

    if (!building){
        return;
    }

    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);
    if (building.uiDataComponent){
        building.uiDataComponent.drawImage(building, world, [rect[0] + 5, rect[1] + 5]);
    }
    ctx.drawImage(getImage(this.entityImage), rect[0] + 5, rect[1] + 5);

    ctx.fillStyle = this.textColor;
    var titleLength = building.identityComponent.name.length;
    var titleFontSize = (titleLength > 20) ? 18 :
        (titleLength > 15) ? 24 :
        36;
    ctx.font = getFont(titleFontSize);
    var titleWidth = ctx.measureText(building.identityComponent.name).width;

    ctx.fillText(building.identityComponent.name, rect[0] + (rect[2] - titleWidth) / 2, rect[1] + 40);

    panelButtons.push(this.drawHelpButton(entity, rect));
    
    ctx.font = getFont(20);

    if (building.personHeldComponent && building.personHeldComponent.personHeld){
        ctx.fillText(sanitize(building.personHeldComponent.personHeld), rect[0] + 10, rect[1] + 75);
    }
    
    var currenciesNeeded, currenciesMade;
    
    if (building.focusPathStopComponent){
        currenciesNeeded = building.focusPathStopComponent.currenciesNeededAtPoint(building, world);
        currenciesMade = building.focusPathStopComponent.currenciesMadeAtPoint(building, world);
    }
    else{
        currenciesNeeded = [];
        currenciesMade = [];
    }

    var startY = rect[1] + 110;

    var description = (building.descriptionComponent && building.descriptionComponent.description.length > 0) ?
        building.descriptionComponent.description :
        undefined;

    if (description){
        ctx.font = '16px OpenSansItalic';

        if (_.isArray(description)){
            _.each(description, function(desc, i){
                ctx.fillText(desc, rect[0] + 35, startY);
                startY += 35;
            });
        }
        else{
            ctx.fillText(description, rect[0] + 35, startY);
            startY += 90;
        }

        ctx.font = getFont(20);
    }

    var lines = [];
    

    if (building.timedDeathComponent){
        lines.push('TIME LEFT: ' + Math.floor(building.timedDeathComponent.timeToDeath / PARAMETERS.ticksPerTick[0]));
    }

    if (currenciesMade.length > 0 && !building.emotionSourceComponent && !building.depositComponent){
        lines.push('MAKES:     ' + sanitize(currenciesMade));
    }
    
    if (building.resourceComponent && building.resourceComponent.resourceCount){
        lines.push('' + building.resourceComponent.resourceCount + ' left');
    }
    if (building.depositComponent){
        lines.push('Built by ' + building.identityComponent.sourceName);
        lines.push('HOLDS:     ' + sanitize(currenciesMade));
        var amountLeft = _.reduce(building.depositComponent.deposit, addFunction, 0);
        lines.push('' + amountLeft + ' left');
    }
    if (building.damageComponent){
        lines.push('DAMAGE DONE: ' + building.damageComponent.damage);
        var line = 'CHARGES HELD:  ' + building.damageComponent.charges + ' / ' + building.damageComponent.maxCharges;
        if (building.damageComponent.maxCharges > building.damageComponent.charges){
            line += '  (start train to recharge)'
        }
        lines.push(line);
    }
    if (building.emotionSourceComponent){
        lines.push('EMOTION LEFT:' + reduceArray(building.emotionSourceComponent.emotions));
        var sourceEntity = world.entityForUid(building.identityComponent.sourceId);
        if (sourceEntity){
            lines.push('SOURCE: ' + sourceEntity.identityComponent.name);
        }
    }
    if (building.focusPathStopComponent && building.focusPathStopComponent.currencyEntities){
        if (_.isArray(building.focusPathStopComponent.currencyEntities) ||
            _.isString(building.focusPathStopComponent.currencyEntities)){
            var colorText = {
                anger: '#660000',
                sadness: '#000066',
                fear: '#660066',
                joy: '#dddd00'
            };
            
            var st = sanitize(building.focusPathStopComponent.currencyEntities);
            var params = allArgs[building.focusPathStopComponent.currencyEntities];
            if (params && params.emotionsToAdd){
                var emotion = Object.keys(params.emotionsToAdd)[0];
                var color = colorText[emotion];
                emotion = emotion.charAt(0).toUpperCase() + emotion.slice(1);
                st = emotion + ' due to ' + st;
                lines.push({
                    text: 'MAKES: ' + st,
                    color: color
                })
            }
            else{
                lines.push('MAKES:  ' + st);
            }
        }
    }
    if (building.dailyEntityMakerComponent){
        var daysLeft = building.dailyEntityMakerComponent.dayCount;
        daysLeft = (daysLeft > 1) ? (daysLeft + ' DAYS') : (daysLeft + ' DAY')
        lines.push('MAKES: ' + sanitize(building.dailyEntityMakerComponent.dayStartEntity) + ' IN ' + daysLeft);
    }
    if (building.healthComponent && building.healthComponent.maxHealth > 1){
        lines.push('HEALTH: ' + building.healthComponent.health + '/' + building.healthComponent.maxHealth);
    }
    
    var i;
    
    for (i = 0; i < lines.length; i++){
        var line = lines[i];
        if (line.color){
            ctx.fillStyle = line.color;
            ctx.fillText(line.text, rect[0] + 35, startY);
            ctx.fillStyle = '#000000';
        }
        else{
            ctx.fillText(line, rect[0] + 35, startY);
        }
        startY += 40;
    }

    if (building.focusPathStopComponent && building.focusPathStopComponent.getCurrencyComponent){
        var comp = building.focusPathStopComponent.getCurrencyComponent(building);

        var xDiff = _.chain(comp.origCurrencyRequested)
            .map(function(val, key){
                return ctx.measureText(sanitize(key) + ':').width;
            })
            .max()
            .value() + 60;

        _.each(comp.origCurrencyRequested, function(val, key){
            if (val > 10){
                startY -= 10;
            }
            ctx.fillText(sanitize(key) + ':', rect[0] + 35, startY);
            for (var i = 0; i < val; i++){
                var img = (i < comp.currencyRequested[key]) ? 'currency' : 'filledCurrency';
                img = getImage(img);
                ctx.drawImage(img, rect[0] + xDiff + 25 * (i % 10), startY - 17 + Math.floor(i / 10) * 25);
            }
            startY += 40;
        });
    }

    if (building.flipComponent){
        var flipRect = [rect[0] + rect[2] / 2 - 100, startY + 20, 200, 30];
        var flipName = allArgs[building.flipComponent.flipEntity];
        this.drawPanelButton(flipRect, 'Flip to ' + flipName);
        panelButtons.push([rect, flipEntity]);
    }

    if (building.interactionComponent.canInteractSelf()){
        var paths = _.filter(world.entities, function(worldEntity){
            return worldEntity.trainPathComponent &&
                _.contains(worldEntity.trainPathComponent.trainStops, building.uid);
        });

        var pathRect = [rect[0] + rect[2] / 2 - 100, rect[1] + rect[3] - 100, 200, 30];

        if (paths.length > 0){
            var path = paths[0];
            if (path.trainPathComponent.canMakeTrain(path, world)){
                this.drawPanelButton(pathRect, 'SEE ACTIVE TRAIN');
                panelButtons.push([pathRect, entityPanelShowPath]);
            }
            else if (PARAMETERS.buildablePaths){
                this.drawPanelButton(pathRect, 'CONNECT TRACK');
                panelButtons.push([pathRect, entityPanelStartTrack]);
            }
        }
        else if (building.focusPathStopComponent && building.focusPathStopComponent.isPathEnd){
            if (!building.damageComponent || building.damageComponent.charges < building.damageComponent.maxCharges){
                var selfEntity = world.entityForKey(PARAMETERS.self);
                
                if (selfEntity.focusMakingComponent.focusUsing < selfEntity.focusMakingComponent.focusCount){
                    this.drawPanelButton(pathRect, 'SET UP TRAIN');
                    panelButtons.push([pathRect, entityPanelStartPath]);
                }
                else{
                    ctx.fillText('NO FOCUS LEFT', pathRect[0], pathRect[1] + pathRect[3]);
                }
            }
        }
    }
    else{
        ctx.fillText('You do not control this building.', rect[0] + rect[2] / 2 - 100, rect[1] + rect[3] - 70);
    }
 
    return panelButtons;
};

var flipEntity = function(entity, ui){
    var world = ui.world;
    var newEntity = world.makeEntities(entity, entity.flipComponent.flipEntity);
    entity.healthComponent.kill();

    if (entity.timedDeathComponent.timeToDeath){
        newEntity.timedDeathComponent.timeToDeath = entity.timedDeathComponent.timeToDeath;
    }
};

var entityPanelShowPath = function(entity, ui){
    var world = ui.world;
    var path = _.chain(world.entities)
        .filter(function(worldEntity){
            return worldEntity.trainPathComponent && 
                _.contains(worldEntity.trainPathComponent.trainStops, entity.panelComponent.sourceId);
        })
        .first()
        .value();
    
    if (path){
        var uiKey = 'trainPath_' + path.uid;
        var menu = world.entityForKey(uiKey);
        if (!menu){
            menu = makeEcs(PARAMETERS.trainPanel, {
                key: uiKey,
                sourceId: path.uid
            });
            world.addEntity(menu);
        }
        else{
            menu.panelComponent.expandPanel();
        }
    }
};

var entityPanelStartPath = function(entity, ui){
    var building = ui.world.entityForUid(entity.panelComponent.sourceId);
    ui.world.focusPathFromEntity(building);
    
    var menu = ui.world.entityForKey(PARAMETERS.trainPathMakingPanel);
    menu.panelComponent.expandPanel();

    entity.panelComponent.closed = true;
};

var entityPanelStartTrack = function(entity, ui){
    ui.world.togglePathBuilding();
};

var entityPanelTimeOut = function(entity, ui){
    var building = ui.world.entityForUid(entity.panelComponent.sourceId);
    building.timedDeathComponent.timeToDeath = 0;
};


var entityReplaceGetReplaceKeys = function(entity, world){
    if (this.skipFlag && world.flags[this.skipFlag]){
        return;
    }
    
    return this.entitiesToMake;
};


var getXpLevel = function(entity){
    var health = this.xpPerLevel;
    var i;
    for (i = 1; i < this.maxLevel; i++){
        health += i * this.xpPerLevel / 2;
        
        if (entity.healthComponent.health < health){
            break;
        }
    }
    return i;
};

var gainExp = function(entity, world){
    entity.healthComponent.health += 25;
    
    _.chain(world.entities)
        .filter(function(worldEntity){
            return worldEntity.experienceTriggerComponent &&
                worldEntity.experienceTriggerComponent.traitKey == entity.identityComponent.key;
        })
        .each(function(worldEntity){
            world.makeEntities(entity, worldEntity.experienceTriggerComponent.xpEntities);
        });
};

var updateExpansion = function(entity){
    var level = this.getXpLevel(entity);
    if (level > this.currentLevel){
        this.currentLevel = level;
    }
};


var fearTickModifyInteraction = function(entity, world, tower, train){
    if (this.fearFrozen > 0){
        this.fearFrozen -= 1;
    }
    else if (percentCheck(5)){
        this.fearFrozen = 3;
    }
    return this.fearFrozen <= 0;
};


var featureItemActionExec = function(entity, world){
    entity.currency[this.execCurrencyKey] += this.execCurrencyChange;
};


var flagBranchGetReplaceKeys = function(entity, world){
    return world.flags[this.flagToCheck] ? this.flagEntities : this.notFlagEntities;
};


var flaggedMakeGetReplaceKeys = function(entity, world){
    if (!world.flags[this.flagToCheck]){
        world.flags[this.flagToCheck] = true;
        return this.entitiesToMake;
    }
    return false;
};


var focusPanelRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    entity.panelComponent.panelButtons = [];
    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);

    var selfEntity = ui.world.entityForKey(PARAMETERS.self);
    
    if (!this.toggleFocusPath){
        this.toggleFocusPath = function(){
            ui.world.toggleFocusPath();
            ui.expandPanel(PARAMETERS.trainPathMakingPanel);
        };

        this.showFocusPanel = function(){
            ui.expandPanel(PARAMETERS.allTrainPanel);
        };
    }

    ctx.fillStyle = this.textColor;


    var lostControl = ui.world.lostControl();
    var focusPanelRect = [rect[0] + rect[2] / 2 - 75, rect[1] + 10, 150, 30];

    if (lostControl){
        var textColor = this.textColor;
        this.textColor = '#cc0000';
        this.drawPanelButton(focusPanelRect, 'LOST CONTROL');
        
        
        var healthText = 'HEALTH: ' + selfEntity.healthComponent.health + '/' + selfEntity.healthComponent.maxHealth

        ctx.fillText(healthText, rect[0] + 30, rect[1] + 60);
        this.textColor = textColor;
    }
    else{
        var focusText = 'Trains used - ' + selfEntity.focusMakingComponent.focusUsing + ' / ' + selfEntity.focusMakingComponent.focusCount;
        
        if (selfEntity.focusMakingComponent.focusUsing === 0){
            this.insetColor = '#cc0000';
            this.textColor = this.insetColor;

            this.drawPanelButton(focusPanelRect, focusText);
            
            this.insetColor = '#000000';
            this.textColor = '#000000';
        }
        else{
            this.drawPanelButton(focusPanelRect, focusText);
        }
        
        entity.panelComponent.panelButtons.push([focusPanelRect, this.showFocusPanel]);

        var fraction = 1 - (selfEntity.focusTickerComponent.ticks / selfEntity.focusTickerComponent.impulseTicks);
        fraction = (fraction === 0) ? 1 : fraction;
        drawBar([focusPanelRect[0], focusPanelRect[1] + 40, focusPanelRect[2], 5], 
                fraction);

        ctx.fillStyle = this.textColor;
        var efficiency = Math.floor(100 * selfEntity.focusMakingComponent.focusEfficiency());
        ctx.fillText('(EFFICIENCY: ' + efficiency + '%)', focusPanelRect[0], focusPanelRect[1] + 70);
    }
    
};


var updateCurrencyDictWithStop = function(stop, world, currencyDict){
    _.each(this.currenciesMadeAtPoint(stop, world), function(currency){
        incrementDict(currencyDict, currency, -1);
    });

    _.each(this.currenciesNeededAtPoint(stop, world), function(currency){
        incrementDict(currencyDict, currency);
    });
};

var currenciesExistAtPoint = function(entity, world){
    var currenciesAtPoint = _.filter(world.entities, function(worldEntity){
        return worldEntity.pathVelocityComponent &&
            worldEntity.positionComponent.comparePos(entity.positionComponent);
    });

    return _.all(this.currenciesMadeAtPoint(entity, world), function(currency){ 
        return _.any(currenciesAtPoint, function(currencyAtPoint){
            return currencyAtPoint.identityComponent.key == currency;
        });
    });
};

var checkFocusStopDisabled = function(entity, world){
    var chkEnables = () => {
        return ((this.enableChecks.length > 0) &&
                _.all(this.enableChecks, function(chkKey){ return !world.entityForKey(chkKey); }));
    }; 
    var chkRequiredOpinions = () => {
        ((this.requiredOpinions.length > 0) &&
         entity.personHeldComponent &&
         _.all(this.requiredOpinions, function(opinion){
             return !_.any(world.entitiesForKey(opinion), function(opinionEntity){
                 return opinionEntity.personHeldComponent.personHeld == entity.personHeldComponent.personHeld;
             });
         })); 
    };
    var chkDisablingEntity = entity.managedComponent &&
        _.any(world.entities, function(worldEntity){
            return worldEntity.disableTraitComponent && worldEntity.disableTraitComponent.checkTraitDisabled(entity);
        });

    return chkDisablingEntity || chkEnables() || chkRequiredOpinions();
};


var focusRender = function(rect, entity, ui){
};


var aliveMakerFocusTick = function(entity, world){
    world.makeEntities(entity, this.aliveEntities);
};


var fullMenuOnClick = function(entity, world, ui){
    var uiKey = this.uiKey;
    var menu = world.entityForKey(uiKey);
    if (!menu){
        menu = makeEcs(this.panelKey, {
            key: uiKey,
            sourceId: entity.uid,
            entityImage: this.image,
            size: (entity.descriptionComponent && entity.descriptionComponent.description.length > 0) ? [550, 400] : [425, 300]
        });
        ui.world.addEntity(menu);
    }
    
    menu.panelComponent.expandPanel();
    
    var rect = world.hexMap.cellForPosComp(entity.positionComponent).rect;

    menu.absolutePositionComponent.x = rect[0] + rect[2];
    menu.absolutePositionComponent.y = rect[1] + rect[3];

    world.addEntity(makeEcs(PARAMETERS.notification, {
        notificationKey: PARAMETERS.openMenu,
        notificationArgs: {
            menuSourceKey: entity.uid
        }
    }));
};

var getUiKey = function(key, uid){
    return key + '_' + uid + '_menu';
};


var gainControlMenuRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    var animateBack = false;
    if (this.percentageComplete > 100){
        this.renderTime -= lastInterval;
        if (this.renderTime < 0){
            entity.healthComponent.kill();
            return;
        }
        animateBack = true;
    }
    else if (this.renderTime < this.fullAnimationTime){
        this.renderTime += lastInterval;
        animateBack = true;
    }

    if (animateBack){
        var fraction = this.renderTime / this.fullAnimationTime;
        ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2] * fraction, rect[3] * fraction);
        return;
    }

    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);
    ctx.fillStyle = '#' + this.textColor;
    ctx.font = getFont(35);
    var txt = 'Regain Control';
    ctx.fillText(txt, rect[0] + (rect[2] - ctx.measureText(txt).width) / 2, rect[1] + 40);

    ctx.font = '16px OpenSansItalic';
    ctx.fillText(this.text, rect[0] + (rect[2] - ctx.measureText(this.text).width) / 2, rect[1] + 100);

    ctx.font = BASE_FONT;
    ctx.fillStyle = '#000000';
    txt = 'Keep your mind inside the bar to regain control.';
    ctx.fillText(txt, rect[0] + (rect[2] - ctx.measureText(txt).width) / 2, rect[1] + 140);
    
    ctx.fillStyle = '#' + this.barColor;
    ctx.fillRect(rect[0] + 10, rect[1] + this.barPos[1], rect[2] - 20, 40);
    
    this.barPos[0] = ui.game.lastPos[0] - (this.barWidth / 2) - rect[0];
    this.barPos[0] = clamp(this.barPos[0], rect[2] - 10 - this.barWidth, 10);

    ctx.fillStyle = '#dddddd';
    
    var controlRect = [rect[0] + this.barPos[0], rect[1] + this.barPos[1], this.barWidth, 40];
    ctxFillRect(controlRect);
    
    var brainRect = [rect[0] + this.brainPos[0], rect[1] + this.brainPos[1], 40, 35];
    ctx.drawImage(getImage(this.brainImage), brainRect[0], brainRect[1]);

    if (collideRect(controlRect, brainRect)){
        this.percentageComplete += 25 * lastInterval;
    }
    else{
        this.percentageComplete -= 20 * lastInterval;
        this.percentageComplete = max(this.percentageComplete, 0);
    }
    
    this.barWidth += 25 * lastInterval;
    this.barWidth = min(this.barWidth, rect[2] - 20);
    
    if (this.resetVelTime <= 0){
        this.brainVel = ((Math.random() * 4) - 2) * 60;
        this.resetVelTime = 1;
    }
    else{
        this.resetVelTime -= lastInterval;
    }
    
    this.brainPos[0] += this.brainVel * lastInterval;
    this.brainPos[0] = clamp(this.brainPos[0], rect[2] - 62, 10);

    if (this.percentageComplete < 100){
        ctx.fillStyle = '#ffffff';
        ctx.strokeStyle = '#ffffff';
        var lineWidth = ctx.lineWidth;
        ctx.lineWidth = 5;

        ctx.beginPath();
        var startAngle = Math.PI * -0.5;
        var endAngle = 2 * Math.PI * this.percentageComplete / 100 + startAngle;
        ctx.arc(rect[0] + rect[2] / 2, rect[1] + 300, 40, startAngle, endAngle);
        ctx.stroke();

        ctx.lineWidth = lineWidth;

        ctx.fillText('' + Math.floor(this.percentageComplete) + '%', rect[0] + rect[2] / 2 - 10, rect[1] + 300);
    }
};


var killLostControlExec = function(entity, world){
    _.chain(world.entities)
        .filter(worldEntity => worldEntity.holdControlComponent)
        .each((worldEntity) => { worldEntity.healthComponent.kill(); });
};


var gameEndRender = function(){
    ctx.fillStyle = '000000';
    ctx.fillRect(0, 0, width, height);
    ctx.font = getFont(40);
    ctx.fillStyle = '#ffffff';
    var txt = 'GAME OVER';
    var textWidth = ctx.measureText(txt).width;
    ctx.fillText(txt, (width - textWidth) / 2, height);
};


var checkStageComplete = function(entity, notificationArgs){
    if (entity.stageChangeComponent.goalsToCheck[notificationArgs.key]){
        entity.stageChangeComponent.goalsToCheck[notificationArgs.key] -= 1;
        entity.stageChangeComponent.shouldChange = _.all(entity.stageChangeComponent.goalsToCheck, function(val){
            return val <= 0;
        });
    }
};


var gameStageDayEnd = function(entity, world){
    world.trackActionables();
    this.daysLeft -= 1;
    if (this.daysLeft <= 0 && entity.stageChangeComponent.checkAndChange(entity, world)){
        entity.healthComponent.health = 0;
    }
    else{
        var dayEntity = _.filter(world.entities, function(worldEntity){
            return worldEntity.dayCounterComponent;
        })[0];
        
        var dayCount = dayEntity.dayCounterComponent.dayCount + 1;

        _.each(world.entities, function(worldEntity){
            if (worldEntity.panelComponent && worldEntity.panelComponent.canClose){
                worldEntity.panelComponent.closed = true;
            }
        });
    }
};


var checkAndChangeGameState = function(entity, world){
    if (this.shouldChange){
        _.each(this.executables, function(exec){
            exec.execute(entity, world);
        });
        return true;
    }
    return false;
};


var canMakeGoal = function(world){
    return world.entityForKey(this.entityKey) === undefined &&
        world.entityForKey(this.constructionKey) === undefined &&
        _.all(this.disablingEntities, function(disablingKey){ return world.entityForKey(disablingKey) === undefined; }) &&
        _.all(this.requiredEntities, function(requiredKey){ return world.entityForKey(requiredKey); });
};

var makeGoal = function(world, pos, entity, interactionKey){
    entity.buttonControlComponent.isNew = false;
    var manager = world.entityForKey(this.managerKey);
    if (manager){
        manager.entityManagerComponent.checkForNewManaged(manager, world);
    }


    var args = {
        x: pos[0],
        y: pos[1],
        sourceKey: this.managerKey,
        sourceTrait: this.managerKey
    };

    if (interactionKey){
        args.interactionKeys = [interactionKey];
    }

    if (entity.personHeldComponent){
        args.personHeld = entity.personHeldComponent.personHeld;
    }

    return makeEcs(this.constructionKey, args);
};


var goalCompleteExec = function(entity, world){
    world.addEntity(makeEcs(PARAMETERS.notification, {
        notificationKey: PARAMETERS.goalComplete,
        notificationArgs: {
            key: entity.identityComponent.key
        }
    }));
};


var goalCompleteMenuRender = function(rect, entity, ui){
    entity.panelComponent.panelButtons = [];

    if (entity.panelComponent.closed || entity.panelComponent.minimized){
        return;
    }

    this.snapPanelPos(entity);

    if (this.height !== undefined){
        rect[3] = this.height;
        entity.absolutePositionComponent.size[1] = this.height;
    }

    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);
    
    var world = ui.world;
    
    var name = this.endGame ? 'GAME OVER' : entity.identityComponent.name;
    var completeText = this.completeText;

    var actionables = world.getActionables();

    var modifier = _.filter(actionables, function(actionable){ return actionable.menuModifierComponent; })[0];
    var randomMarker = _.filter(actionables, function(actionable){ return actionable.randomMenuComponent; })[0];
    actionables = _.filter(actionables, function(actionable){ return actionable.uiActionComponent; });
    
    if (modifier){
        name = modifier.menuModifierComponent.name ? modifier.menuModifierComponent.name : name;
        completeText = modifier.menuModifierComponent.completeText ? modifier.menuModifierComponent.completeText : completeText;
    }

    if (!(this.showPoints || completeText || actionables.length > 0)){
        entity.panelComponent.closed = true;
        return;
    }

    if (this.renderTime < this.titleTime){
        return;
    }

    ctx.fillStyle = this.textColor;

    if (this.sourceTrait){
        var traitImage = traitImageForKey(this.sourceTrait, world);
        
        if (traitImage){
            ctx.drawImage(getImage(traitImage), rect[0] + 5, rect[1] + 5);
        }
    }

    ctx.drawImage(getImage(this.image), rect[0] + 5, rect[1] + 5);
    ctx.font = (name.length > 25) ? getFont(20) : getFont(36);
    ctx.fillText(name, rect[0] + 85, rect[1] + 50);


    if (randomMarker){
        if (!this.carousel){
            this.carousel = makeEcs('randomCarousel');
            this.carousel.setMarker(randomMarker);
        }

        if (!this.carousel.animationDone){
            this.carousel.render([rect[0] + (rect[2] - 100) / 2, rect[1] + 200], this.renderTime - this.titleTime);

            if (this.carousel.animationDone){
                this.renderTime = this.titleTime;
            }
            return;
        }
    }

    if (this.renderTime < this.descriptionTime){
        return;
    }

    var y = rect[1] + 100;

    if (this.showingDescription){
        ctx.font = '20px OpenSansItalic';
        
        if (_.isArray(completeText)){
            _.each(completeText, function(line, i){
                ctx.fillText(line, rect[0] + 20, rect[1] + 120 + i * 25);
            });
            y += 20 * completeText.length;
        }
        else{
            ctx.fillText(completeText, rect[0] + 20, rect[1] + 120);
            y += completeText.length ? 25 : 0;
        }

        y = rect[1] + 200;

        var pathXOffset = 0;
        if (entity.goalCompleteMenuComponent.path && entity.goalCompleteMenuComponent.path.length > 0){
            ctx.fillText('Path Taken', rect[0] + 20, y);
            y += 50;
            pathXOffset = 200;
        }

        _.each(entity.goalCompleteMenuComponent.path, (pathPieces, i) => {
            var timePerRow = 0.25;
            var timeBeforeRender = this.descriptionTime + 0.25 * (1 + i);
            if (this.renderTime < timeBeforeRender){
                return;
            }
            var scale = (this.renderTime - timeBeforeRender) / 0.25;
            scale = min(scale, 1);

            if (pathPieces.traitImage){
                ctx.drawImage(getImage(pathPieces.traitImage), rect[0] + 20, y - 32, 60 * scale, 52 * scale);
            }
            ctx.drawImage(getImage(pathPieces.image), rect[0] + 20, y - 32, 60 * scale, 52 * scale);
            if (scale == 1){
                ctx.fillText(pathPieces.name, rect[0] + 80, y);
            }
            y += 60;
        });
        
        if (this.time < this.fullAnimationTime && completeText){
            return;
        }
    }
    else{
        ctx.font = getFont(20);

        var traits = _.chain(actionables)
            .filter(function(actionable){
                return actionable.entityManagerComponent;
            })
            .map(function(actionable){ return actionable.identityComponent.key; })
            .value();
        
        actionables = _.filter(actionables, function(actionable){
            return !(actionable.buttonControlComponent &&
                     _.contains(traits, actionable.buttonControlComponent.managerKey));
        });
        
        _.each(actionables, (entityMade) => {
            entityMade.uiDataComponent.drawImage(entityMade, world, [rect[0] + 15, y - 1]);
            
            ctx.fillText(entityMade.identityComponent.name, rect[0] + 90, y + 21);

            var x = rect[0] + rect[2] - 100;

            _.each(entityMade.uiActionComponent.getUiActions(entityMade, ui, entity), (fn, key) => {
                var rect = [x, y + 5, 85, 30];
                this.drawPanelButton(rect, key);
                entity.panelComponent.panelButtons.push([rect, fn]);

                x -= 100;
            });
            
            ctx.strokeStyle = this.insetColor;
            ctxRoundedRect([rect[0] + 5, y - 25, rect[2] - 10, 90]);
            
            y += 100;
        });
    }
    
    ctx.font = getFont(20);

    var closeRect = [rect[0] + rect[2] / 2 - 100, rect[1] + rect[3] - 50, 200, 40];

    if (entity.rebuildMenuComponent && this.showingDescription && !this.endGame){
        var rebuildFunction = entity.rebuildMenuComponent.getRebuildFunction(ui);
        if (rebuildFunction){
            var panelRect = [closeRect[0] + pathXOffset, closeRect[1] - 250, closeRect[2], 40];
            this.drawPanelButton(panelRect, 'REBUILD');
            entity.panelComponent.panelButtons.push([panelRect, rebuildFunction]);
            y += 50;
        }
    }
    
    if (actionables.length > 0){
        var flipRect;
        if (this.showingDescription){
            flipRect = [closeRect[0] + pathXOffset, closeRect[1] - 350, closeRect[2], closeRect[3] + 50];
            this.drawPanelButton(flipRect, 'SHOW UNLOCKS');
        }
        else{
            flipRect = [closeRect[0], closeRect[1] - 50, closeRect[2], closeRect[3]];
            this.drawPanelButton(flipRect, 'SHOW DESCRIPTION');
        }
        entity.panelComponent.panelButtons.push([flipRect, this.getFlipModeFunction()]);
    }


    this.drawPanelButton(closeRect, this.endGame ? 'END GAME' : 'CLOSE');
    
    if (!this.closeFunction){
        this.closeFunction = () => {
            entity.healthComponent.kill();
            entity.panelComponent.closed = true;
            if (this.endGame){
                window.location = 'select.html';
            }
        };
    }

    entity.panelComponent.panelButtons.push([closeRect, entityPanelClose]);
    
    ctx.font = BASE_FONT;
    return false;
};

var goalCompleteMenuFlipMode = function(){
    if (!this.flipModeFunction){
        var that = this;
        this.flipModeFunction = function(){
            that.showingDescription = !that.showingDescription;
        };
    }
    return this.flipModeFunction;
};


var goalCompleteMenuCreateExec = function(entity, world){
    var actionables = world.getActionables();
    if (!(this.showPoints || 
          entity.rendererComponents[0].completeText || 
          entity.rebuildMenuComponent && entity.rebuildMenuComponent.getRebuildButton(world) ||
          actionables.length > 0)){
        entity.healthComponent.kill();
    }
    
    _.chain(world.entities)
        .filter(function(worldEntity){
            return worldEntity.goalCompleteMenuComponent &&
                worldEntity.uid != entity.uid;
        })
        .each(function(worldEntity){
            worldEntity.healthComponent.kill();
        });

    if (this.source && this.source.uiDataComponent){
        entity.goalCompleteMenuComponent.path = this.source.uiDataComponent.lastPath;
        this.source = undefined;
    }
};

var traitImageForKey = function(traitKey, world){
    var trait = world.entityForUid(traitKey);
    if (trait){
        return trait.uiDataComponent.image;
    }
    else if (allArgs[traitKey]){
        return allArgs[traitKey].image;
    }
    return "trait";
};


var getRebuildButton = function(world){
    return _.chain(world.entities)
        .filter((worldEntity) => {
            return worldEntity.buttonControlComponent &&
                worldEntity.buttonControlComponent.entityKey == this.sourceKey;
        })
        .filter(function(button){
            return button.buttonControlComponent.canMakeEntity(world);                    
        })
        .first()
        .value();
};

var getRebuildFunction = function(ui){
    var world = ui.world;
    if (this.rebuildFunction === undefined){
        var button = this.getRebuildButton(ui.world);
        
        if (button){
            this.rebuildFunction = button.buttonControlComponent.getWrappedFunction(button, ui.world, ui);
        }
        else{
            this.rebuildFunction = false;
        }
    }
    
    return this.rebuildFunction;
};


var healEntities = function(entity, world){
    _.each(this.entitiesToHeal, function(val, key){
        _.each(world.entitiesForKey(key), function(entityToHeal){
            entityToHeal.healthComponent.health += val;
        });
    });
};


var healthBleedTick = function(entity){
    entity.healthComponent.health -= 1;
};


var killHealthComponent = function(){
    this.health = 0;
};


var healthModifyAmount = function(){
    return this.activated ? this.activeHealthChange : this.idleHealthChange;
};


var helpInfoPanelRender = function(rect, entity, ui){
    var panelButtons = [];

    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);

    ctx.fillStyle = this.textColor;
    ctx.font = getFont(36);
    var titleWidth = ctx.measureText(entity.identityComponent.name).width;
    ctx.fillText(entity.identityComponent.name, rect[0] + (rect[2] - titleWidth) / 2, rect[1] + 50);
    
    ctx.font = getFont(20);
    _.each(this.helpLines, function(line, i){
        ctx.fillText(line, rect[0] + 10, rect[1] + 150 + 50 * i);
    });

    return panelButtons;
};


var openHelpPanel = function(entity, ui){
    var sourceEntity = ui.world.entityForUid(entity.panelComponent.sourceId);

    var panelKey = _.chain(csvIdentifiers.helpInfoPanel)
        .filter(function(helpInfoPanelKey){
            var helpInfoPanelArgs = allArgs[helpInfoPanelKey];
            return _.any(helpInfoPanelArgs.components, function(component){
                return sourceEntity[component];
            });
        })
        .first()
        .value();

    ui.expandPanel(panelKey);
};


var hitRender =  function(rect, entity, ui, rectCount){
    if (this.wasHit){
        var emotionRect = getEmotionRect(rect, entity, rectCount, ui);
        ctx.fillStyle = '#ffffff';
        ctx.fillRect(emotionRect[0], emotionRect[1], emotionRect[2], emotionRect[3]);
        this.wasHit = false;
    }
};


var imageRender = function(rect, entity){
    var image = getImage(this.image);
    ctx.drawImage(image, rect[0], rect[1]);
};


var impulseFocusStopInteractWithTrain = function(entity, world, train){
    var currencies = world.makeEntities(entity, this.impulseCurrency);
    var carriage = train.trainComponent.getCurrentCarriage(train, world);
    carriage.carriageComponent.holding = _.map(currencies, getUid);
    entity.healthComponent.health = 0;
    return false;
};

var impulseFocusStopCurrenciesMadeAtPoint = function(entity){
    return [this.impulseCurrency];
};


var resetEmotionSource = function(){
    this.spawnCount = 0;
};


var instantEmotionResourceTick = function(entity, world){
    entity.focusTickResponseComponent.focusTick(entity, world);
};


var canInteractSelf = function(){
    return this.canInteract(PARAMETERS.self);
};

var canInteract = function(key){
    return _.contains(this.interactionKeys, key);
};


var makeIsaacLifecycleEntities = function(entity, world){
    this.makeLifecycleEntities(entity, world, this.isaacEntities);
};


var junctionRender = function(rect){
    ctx.fillStyle = '#ff0000';
    ctx.beginPath();
    ctx.arc(rect[0] + rect[2] / 2, rect[1] + rect[3] / 2, 10, 0, 2 * Math.PI);
    ctx.fill();
};


var junctionItemForKey = function(key){
    for (var i = 0; i < this.heldItems.length; i++){
        if (this.heldItems[i].identityComponent.key == key &&
            this.heldItems[i].healthComponent.health > 0){
            return this.heldItems[i];
        }
    }
    return undefined;
};


var killCurrencyExec = function(entity, world){
    _.chain(world.entities)
        .filter((worldEntity) => {
            return (worldEntity.identityComponent && 
                    worldEntity.identityComponent.key == this.currencyToKill &&
                    !worldEntity.pathVelocityComponent.isHeld) ||
                (worldEntity.depositComponent && 
                 worldEntity.depositComponent.deposit[this.currencyToKill] &&
                 worldEntity.depositComponent.deposit[this.currencyToKill] > 0);
        })
        .each(function(worldEntity){
            worldEntity.healthComponent.health = 0;
        });
};


var dayEndKillEntity = function(entity, world){
    entity.healthComponent.health = 0;
};


var killEntity = function(entity){
    entity.healthComponent.kill();
};


var executeKillEntities = function(entity, world){
    _.each(this.entitiesToKill, function(key){
        _.each(world.entitiesForKey(key), function(entity){
            entity.healthComponent.kill();
        });
    });
};


var killIfFlagExec = function(entity, world){
    if (this.killIfFlag && world.flags(this.killIfFlag)){
        entity.healthComponent.kill();
    }
};


var killTrainExec = function(entity, world){
    _.chain(world.entities)
        .filter((entity) => {
            return entity.trainVelocityComponent &&
                _.contains(entity.trainVelocityComponent.trainStops, this.source.uid);
        })
        .each(function(entity){
            entity.healthComponent.kill();
        });
};


var killTraitExec = function(entity, world){
    _.chain(world.entities)
        .filter((worldEntity) => {
            return (worldEntity.identityComponent && _.contains(worldEntity.identityComponent.tags, this.traitToKill)) ||
                (worldEntity.managedComponent && worldEntity.managedComponent.managerKey == this.traitToKill) ||
                (worldEntity.identityComponent && worldEntity.identityComponent.key == this.traitToKill) ||
                (worldEntity.sourceExtensionComponent && worldEntity.sourceExtensionComponent.sourceKey == this.traitToKill);
        })
        .each(function(worldEntity){ 
            if (worldEntity.healthComponent){
                worldEntity.healthComponent.health = 0;
            }
        });
};


var lostControlDeathExec = function(entity, world){
    _.chain(world.entities)
        .filter(function(worldEntity){ return worldEntity.loseControlExec; })
        .each(function(worldEntity){ worldEntity.loseControlExec.execute(worldEntity, world); });
};


var makeGainControlMenuExec = function(entity, world){
    world.makeEntities(entity, this.gainControlMenuKey + '_' + this.emotion, {
        emotion: this.emotion
    });
};


var timeForceExec = function(entity, world){
    world.game.ticksPerTick = entity.timeForceComponent.ticksPerTick;
    world.game.tickSystemWrapper.running = true;
};


var makeAllGetReplaceKeys = function(){
    return csvIdentifiers[this.csv];
}


var makeCurrencyRequest = function(entity, world){
    var request = makeEcs(this.requestKey, {
        currencyRequested: _.clone(this.currencyRequested),
        x: entity.positionComponent.x,
        y: entity.positionComponent.y
    });
    world.addEntity(request);
};


var executeMakeEntities = function(entity, world){
    var args = {};

    if (entity.identityComponent){
        args.startEntityKey = entity.identityComponent.key;
    }
    

    var madeEntities = world.makeEntities(entity, this.entitiesToMake, args);
    if (this.adjacent && madeEntities.length > 0){
        var firstEntity = madeEntities[0];
        var pos = [firstEntity.positionComponent.x, firstEntity.positionComponent.y];
        var neighbors = _.chain(world.hexMap.neighbors(pos[0], pos[1]))
            .filter(function(neighbor){
                return world.isPosBuildable(neighbor);
            })
            .shuffle()
            .value();
        
        for (var i = 1; i < madeEntities.length; i++){
            if (madeEntities[i].positionComponent){
                madeEntities[i].positionComponent.x = neighbors[i - 1][0];
                madeEntities[i].positionComponent.y = neighbors[i - 1][1];
            }
        }
    }
};


var makeIfMissingExec = function(entity, world){
    if (!world.entityForKey(this.missingKey)){
        world.makeEntities(this.source, this.entitiesToMake);
    }
};


var makeParticleEffect = function(entity, world){
    var rect =  world.hexMap.cellForPosComp(entity.positionComponent).rect;
    world.makeEntities(entity, this.particleKey, {
        effectPos: [rect[0] + rect[2] / 2, rect[1] + rect[3] / 2]
    });
};


var makeRandomMultipleGetReplaceKeys = function(entity, world){
    var numberOfProblems = (Math.random() * (this.count - this.minCount)) + this.minCount;
    var replaceKeys = [];
    for (var i = 0; i < numberOfProblems; i++){
        replaceKeys.push(this.entitiesToMake);
    }
    return replaceKeys;
};


var addExperienceToManager = function(entity, world){
    var managingEntity = world.entityForKey(this.managerKey);
    
    if (!managingEntity){
        managingEntity = _.chain(world.entities)
            .filter(function(worldEntity){
                return (worldEntity.sourceExtensionComponent || worldEntity.entityManagerComponent) &&
                    worldEntity.positionComponent.comparePos(entity.positionComponent);
            })
            .first()
            .value();
        if (managingEntity && managingEntity.sourceExtensionComponent){
            managingEntity = world.entityForKey(managingEntity.sourceExtensionComponent.sourceKey);
        }
    }

    if (managingEntity){
        managingEntity.experienceComponent.gainExp(managingEntity, world);
    }
};

var isManagingEntity = function(managingEntity){
    return (managingEntity.identityComponent && managingEntity.identityComponent.key == this.managerKey) ||
        (managingEntity.sourceExtensionComponent && managingEntity.sourceExtensionComponent.sourceKey == this.managerKey);
};


var mapSpawnPos = function(entity, world){
    return _.chain(world.hexMap.neighbors(entity.positionComponent.x,
                                          entity.positionComponent.y))
        .filter(function(neighbor){ return world.isPosBuildable(neighbor); })
        .sample()
        .value();
};

var mapSpawn = function(entity, world, spawnedEntities){
    var pos = this.mapSpawnPos(entity, world);

    if (spawnedEntities){
        var attempts = 0;
        while (_.any(spawnedEntities, function(spawnedEntity){ return spawnedEntity.positionComponent.isPos(pos); })){
            attempts += 1;
            if (attempts > 10){
                pos = undefined;
                break;
            }
            pos = this.mapSpawnPos(entity, world);
        }
    }

    if (pos){
        var key = _.isFunction(this.mapSpawnKey) ? this.mapSpawnKey(entity, world) : this.mapSpawnKey;
        if (key){
            var newEntity = makeEcs(key, {
                x: pos[0],
                y: pos[1],
                source: entity
            });
            world.addEntity(newEntity);
            this.mapPostSpawn(entity, world, newEntity);
            return newEntity;
        }
    }
    return false;
};


var markTraitNewExec = function(entity, world){
    var managerKey = entity.buttonControlComponent.managerKey;
    var manager = world.entityForKey(managerKey);
    if (manager && entity.healthComponent.health > 0){
        if (manager.interactionComponent.canInteractSelf() && entity.interactionComponent.canInteractSelf()){
            manager.entityManagerComponent.hasNew = true;
        }

        var rect =  world.hexMap.cellForPosComp(manager.positionComponent).rect;
        world.makeEntities(manager, this.particleEffect, {
            managerKey: managerKey,
            effectPos: [rect[0] + rect[2] / 2, rect[1] + rect[3] / 2]
        });

        _.chain(world.entities)
            .filter(worldEntity => worldEntity.sourceExtensionComponent && worldEntity.sourceExtensionComponent.sourceKey == managerKey)
            .each((worldEntity) => {
                var rect =  world.hexMap.cellForPosComp(worldEntity.positionComponent).rect;
                world.makeEntities(manager, this.particleEffect, {
                    managerKey: managerKey,
                    effectPos: [rect[0] + rect[2] / 2, rect[1] + rect[3] / 2]
                });
            });
    }
};


var flashbackFunction = function(entity, world){
    if (entity.entityManagerComponent.disabled){
        return;
    }
    
    var emotion = _.sample(entity.memoryComponent.memoryEmotions);

    if (!emotion){
        return;
    }

    for (var i = 0; i < this.flashbackCount; i++){
        var space = entity.entityManagerComponent.findFreeManagedSpace(entity, world);

        if (space){
            world.makeEntities(entity, 'flashback_' + emotion, {
                x: space.positionComponent.x,
                y: space.positionComponent.y,
                sourceTrait: entity.identityComponent.key
            });
        }
    }
};


var memoryTick = function(entity, world){
    var managedEntitiesCount = _.filter(world.entities, function(worldEntity){
        return worldEntity.managedComponent &&
            worldEntity.managedComponent.managerKey == entity.identityComponent.key;
    }).length;
    
    if (managedEntitiesCount > this.lastManagedCount){
        if (entity.timedDeathComponent){
            entity.timedDeathComponent.timeToDeath += 50 * managedEntitiesCount - this.lastManagedCount;
        }
        this.lastManagedCount = managedEntitiesCount;
    }
};


var memoryStartLifecycle = function(entity, world){
    this.entitiesMade = _.chain(world.entities)
        .filter(function(emotionResourceMap){
            return emotionResourceMap.emotionResourceMapComponent &&
                _.contains(entity.memoryComponent.memoryEmotions, emotionResourceMap.emotionResourceMapComponent.emotionToMap);
        })
        .map(function(emotionResourceMap){
            return world.makeEntities(entity, emotionResourceMap.emotionResourceMapComponent.emotionMappedEntities);
        })
        .flatten(true)
        .map(function(entity){
            return entity.uid;
        })
        .value();
};


var memoryFindPositionExec = function(entity, world){
    var checkedPositions = [];
    var positionsToCheck = [this.startPos];
    var blockingEntities = world.getBlockingEntities();
    var blockingPositions = _.map(blockingEntities, 
                                  blockingEntity => [blockingEntity.positionComponent.x, blockingEntity.positionComponent.y]);

    for (var j = 0; j < this.iterations; j++){
        var nextPositions = [];
        for (var i = 0; i < positionsToCheck.length; i++){
            var checkPos = positionsToCheck[i];

            var posNeighbors = world.neighbors(checkPos);
            var allNeighbors = _.chain(posNeighbors)
                .map(posNeighbor => world.neighbors(posNeighbor))
                .flatten(true)
                .filter(posNeighbor => world.isPosInBounds(posNeighbor))
                .value();

            if (_.all(allNeighbors, neighbor => !_.any(blockingPositions, blockingPos => comparePos(neighbor, blockingPos)))){
                entity.positionComponent.x = checkPos[0];
                entity.positionComponent.y = checkPos[1];
                return;
            }
            else{
                checkedPositions.push(checkPos);
                _.chain(world.neighbors(checkPos))
                    .filter(newPos => world.isPosInBounds(newPos))
                    .filter(newPos => !_.any(checkedPositions, checkedPos => comparePos(checkedPos, newPos)))
                    .filter(newPos => !_.any(nextPositions, checkedPos => comparePos(checkedPos, newPos)))
                    .each(function(newPos){ nextPositions.push(newPos); });
            }
        }
        positionsToCheck = nextPositions;
    }

    if (entity.healthComponent){ //Could not find an open position
        entity.healthComponent.kill();
    }
};


var memoryConstruct = function(entity, world){
    var newEntity = makeEcs(this.constructionIdentifier, {
        x: entity.positionComponent.x,
        y: entity.positionComponent.y,
        sourceTrait: this.sourceKey
    });
    world.addEntity(newEntity);
};


var memoryFadeExec = function(entity, world){
    var newTrait = world.transformTrait(this.sourceKey, this.newTrait, true, true);
    if (newTrait){
        newTrait.fadingMemoryComponent.oldTrait = this.sourceKey;
    }
};


var memoryGoalCompleteExec = function(entity, world){
    if (!entity.managedComponent){
        return;
    }

    var source = world.entityForKey(entity.managedComponent.managerKey);

    if (!source){
        return;
    }
    
    if (this.flareMemory){
        source.memoryComponent.flashbackFunction(source, world);
    }
    if (this.killMemory){
        source.healthComponent.kill()
    }

    _.chain(world.entities)
        .filter((worldEntity) => (worldEntity.memoryFadeComponent &&
                                  worldEntity.memoryFadeComponent.sourceKey == source.identityComponent.key))
        .each((worldEntity) => {
            worldEntity.timedDeathComponent.timeToDeath += this.bonusTime;
        })
};


var triggerFlashback = function(entity, world){
    if (Math.random() < this.flashbackChance){
        var memory = world.entityForKey(entity.managedComponent.managerKey);
        if (memory && memory.memoryComponent){
            memory.memoryComponent.flashbackFunction(memory, world);
        }
    }
};


var menuTutorialTextRender = function(rect, entity, ui){
    this.hasDrawn = true;
    this.menuEntity = _.chain(ui.world.entities)
        .filter((worldEntity) => (worldEntity.panelComponent &&
                                  !(worldEntity.panelComponent.closed || worldEntity.panelComponent.minimized) &&
                                  worldEntity.identityComponent &&
                                  worldEntity.identityComponent.key.indexOf(this.entityToMark) == 0))
        .first()
        .value();
    
    if (!this.menuEntity){
        return;
    }

    this.shownOnce = true;

    rect = this.menuEntity.absolutePositionComponent.getAbsPosRect();

    ctx.fillStyle = '#ffffff';
    ctx.font = getFont((this.text.length > 10) ? 20 : 30);
    var textWidth = ctx.measureText(this.text).width;
    ctx.fillText(this.text, min(rect[0] + this.xOffset, width - textWidth - 10), rect[1] + this.yOffset - 20);
    ctx.font = BASE_FONT;
    
    if (this.shouldDrawArrow){
        this.drawArrow([rect[0] + this.xOffset + 100, rect[1] + this.yOffset - 10],
                       [rect[0] + this.xOffset, rect[1] + this.yOffset]);
    }
};


var menuTutorialDone = function(entity, world){
    var renderComponent = entity.rendererComponents[0];
    if (renderComponent.hasDrawn && renderComponent.menuEntity == undefined){
        if (!renderComponent.shownOnce){
            entity.tutorialTextComponent.nextEntities = undefined;
        }
        return true;
    }
    return false;
};


var nameRender = function(rect){
    ctx.fillStyle = '#ffffff';
    ctx.fillText(this.name, rect[0] + rect[2] / 3, rect[1] + rect[3] / 4);
};


var nextDayEntityDayEnd = function(entity, world){
    _.each(this.execs, function(exec){
        exec.execute(entity, world);
    });
    entity.healthComponent.health = 0;
};


var noFocusNotifierRender = function(rect, entity, ui){
    var self = ui.entityForKey(PARAMETERS.self);
    if (self.focusMakingComponent.focusUsing === 0){
        var entitiesToMark = [];
        var goalButtons = [];

        _.chain(ui.world.entities)
            .filter(worldEntity => {
                if (worldEntity.worldGoalComponent){
                    return true;
                }
                else if (worldEntity.damageComponent && worldEntity.damageComponent.charges < worldEntity.damageComponent.maxCharges){
                    return true;
                }
                return false;
            })
    }
};


var notificationSerialize = function(entity, serialized){
    delete serialized.notificationFunctions;
    return serialized;
};


var addNotificationCurrency = function(entity, args, world){
    world.addCost(entity.notificationCurrencyComponent.currencyName, 
                  entity.notificationCurrencyComponent.notificationCurrency);
};


var notifyEntityMakerFn = function(entity, args, world){
    if (_.all(this.notificationArgs, function(val, key){
        return args[key] == val;
    })){
        this.count -= 1;
        if (this.count <= 0){
            this.count = this.impulseCount;
            world.makeEntities(entity, this.entitiesToMake);
        }
    }
};


var openMenuExecute = function(entity, world){
    if (entity.interactionComponent && entity.interactionComponent.canInteract(PARAMETERS.self)){
        var markerEntity = makeEcs(this.markerKey, {
            entityUid: entity.uid,
            x: entity.positionComponent.x,
            y: entity.positionComponent.y
        });
        world.addEntity(markerEntity);
    }
};


var openMenuOnClick = function(entity, world, ui){
    ui.openPanelAtPos('#' + entity.identityComponent.key, entity.positionComponent);
};


var openMenuMarkerRender = function(rect, entity, ui){
    var entityToClick = ui.world.entityForUid(entity.openMenuMarkerComponent.entityUid);
    if (entityToClick){
        entityToClick.clickComponent.onClick(entityToClick, ui.world, ui);
        entity.healthComponent.health = 0;
    }
};


var generateOpinionIsaacs = function(args){
    var isaacEntities = (args.isaacEntities !== undefined) ? args.isaacEntities : [];
    var mangle = function(key){
        return mangleIdentityWithTrait(key, args.personHeld);
    };
    
    isaacEntities = isaacEntities.concat(_.map(args.buttonKeys, mangle));
    isaacEntities = isaacEntities.concat(_.map(args.opinionActions, mangle));
    
    return isaacEntities;
};


var opinionTick = function(entity, world){
    if (tickComp(this)){
        var person = world.entityForKey(entity.personHeldComponent.personHeld);
        world.makeEntities(person, this.emotionsToMake);
    }
};


var opinionConditionalExec = function(entity, world){
    if (_.any(this.opinions, (opinionKey) => {
        return _.any(world.entitiesForKey(opinionKey), (opinion) => {
            opinion.personHeldComponent.personHeld == this.person;
        });
    })){
        var source = world.entityForUid(this.sourceId);
        world.makeEntities(source, this.entitiesToMake);
    }
};


var pairTransformGetReplaceKeys = function(entity, world){
    var trait1 = world.entityForKey(this.trait1);
    var trait2 = world.entityForKey(this.trait2);

    if (!(trait1 && trait2)){
        return false;
    }

    var trait1InteractionKeys = trait1.interactionComponent.interactionKeys;
    var trait2InteractionKeys = trait2.interactionComponent.interactionKeys;

    var setTrait = function(trait, interactionKeys){
        trait.interactionComponent.interactionKeys = interactionKeys;
        
        _.chain(world.entities)
            .filter(worldEntity => (worldEntity.buttonControlComponent &&
                                    worldEntity.buttonControlComponent.managerKey == trait.identityComponent.key))
            .each(worldEntity => {
                worldEntity.interactionComponent.interactionKeys = interactionKeys;
            });

        _.chain(world.entities)
            .filter(worldEntity => (worldEntity.healthComponent &&
                                    worldEntity.managedComponent &&
                                    worldEntity.managedComponent.managerKey == trait.identityComponent.key))
            .each(worldEntity => worldEntity.healthComponent.kill());
    }

    setTrait(trait1, trait2InteractionKeys);
    setTrait(trait2, trait1InteractionKeys);

    return false;
};


var expandPanel = function(){
    this.minimized = false;
    this.closed = false;
};


var panelUiClick = function(pos, entity, ui){
    _.each(entity.panelComponent.panelButtons, function(pair){
        var rect = pair[0];
        var fn = pair[1];

        if (containsPos(rect, pos)){
            if (ui.gameProperties.settings.sfx){
                var pingEffect = getAudio.get('sounds/beep.ogg');
                pingEffect.play();
            }

            fn(entity, ui);
        }
    });
};


var snapPanelPos = function(entity){
    entity.absolutePositionComponent.y = min(entity.absolutePositionComponent.y, 678 - entity.absolutePositionComponent.size[1]);
    entity.absolutePositionComponent.y = max(entity.absolutePositionComponent.y, 50 - entity.absolutePositionComponent.size[1]);
    entity.absolutePositionComponent.x = min(entity.absolutePositionComponent.x, width - entity.absolutePositionComponent.size[0]);
    entity.absolutePositionComponent.x = max(entity.absolutePositionComponent.x, 50 - entity.absolutePositionComponent.size[0]);
};

var outPanelRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    entity.panelComponent.panelButtons = [];
    if (entity.panelComponent.closed){
        this.renderTime = 0;
        return;
    }

    this.snapPanelPos(entity);

    if (this.renderTime < this.fullAnimationTime){
        this.renderTime += lastInterval;
    }

    if (this.renderTime < this.animatingTime){
        this.renderTime += lastInterval;
        var fraction = this.renderTime / this.animatingTime;
        ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2] * fraction, rect[3] * fraction);
        return;
    }

    var panelButtons = this.specificRender(rect, entity, ui);
    
    if (panelButtons !== false){
        entity.panelComponent.panelButtons = panelButtons;
        
        if (entity.panelComponent.panelButtons !== undefined){
            ctx.font = getFont(20);
            
            var closeRect = [rect[0] + rect[2] / 2 - 50, rect[1] + rect[3] - 50, 100, 40];
            this.drawPanelButton(closeRect, 'CLOSE');
            
            entity.panelComponent.panelButtons.push([closeRect, entityPanelClose]);
        }
    }

    ctx.font = BASE_FONT;
};

var drawPanelButton = function(rect, text){
    ctx.strokeStyle = this.insetColor;
    ctxRoundedRect(rect);
    
    ctx.fillStyle = this.textColor;
    var measure = ctx.measureText(text);
    var textWidth = measure.width;
    ctx.fillText(text, rect[0] + rect[2] / 2 - textWidth / 2, rect[1] + rect[3] / 2 + this.yTextOffset);
};

var drawImageButton = function(rect, img){
    ctx.strokeStyle = this.insetColor;
    ctxRoundedRect(rect);

    img = getImage(img);

    ctx.drawImage(img, rect[0] + (rect[2] - img.width) / 2, rect[1] + (rect[3] - img.height) / 2);
}

var entityPanelClose = function(entity, ui){
    entity.panelComponent.closed = true;
    
    if (entity.panelComponent.sourceId){
        var building = ui.world.entityForUid(entity.panelComponent.sourceId);
        if (building && building.menuCloseComponent){
            building.menuCloseComponent.execute(building, ui.world);
        }
    }
};

var drawHelpButton = function(entity, rect){
    ctx.font = getFont(16);
    var helpRect = [rect[0] + rect[2] - 25, rect[1], 25, 25];
    ctx.strokeStyle = this.insetColor;
    ctx.beginPath();
    ctx.moveTo(helpRect[0], helpRect[1]);
    ctx.lineTo(helpRect[0], helpRect[1] + helpRect[3]);
    ctx.lineTo(helpRect[0] + helpRect[2], helpRect[1] + helpRect[3]);
    ctx.stroke();

    ctx.fillStyle = this.textColor;
    ctx.fillText('?', helpRect[0] + 7, helpRect[1] + helpRect[3] - 5);
    return [helpRect, entity.helpPanelComponent.openHelpPanel];
};


var paramPathExec = function(entity, world){
    var source = world.entityForKey(this.startKey);
    var end = world.entityForKey(this.endKey);
    if (source && end){
        var trainPath = makeEcs(this.trainPathKey, {
            trainStops: [end.uid],
            trainStartId: source.uid,
            focusCost: 0,
            stoppable: false
        });
        world.addEntity(trainPath);
    }
};


var makeParticle = function(){
    return {
        timeLeft: Math.random() * 0.5 + 0.5,
        radial: (Math.random() * 0.5 + 0.5) * this.effectRadius,
        angular: Math.random() * 2 * Math.PI
    };
};

var particleEffectRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    while (this.startParticles > 0){
        this.startParticles -= 1;
        this.particles.push(this.makeParticle());
    }
    this.timeToCheck -= lastInterval;
    if (this.timeToCheck < 0){
        this.timeToCheck += this.impulseTimeToCheck;
        this.particles.push(this.makeParticle());
    }
    
    this.particles = _.filter(this.particles, function(particle){
        particle.timeLeft -= lastInterval;
        return (particle.timeLeft > 0);
    });


    var image = getImage(this.image);
    _.each(this.particles, (particle) => {
        var x = particle.radial * Math.cos(particle.angular);
        var y = particle.radial * Math.sin(particle.angular);
        ctx.drawImage(image, this.effectPos[0] + x, this.effectPos[1] + y);
    });
};


var pathConnectRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    if (ui.world.lostControl()){
        return;
    }

    var endRect = ui.world.hexMap.cellForPosComp({x: entity.pathMoveComponent.endPosition[0],
                                                  y: entity.pathMoveComponent.endPosition[1]}).rect;
    var startPos = [rect[0] + rect[2] / 2, rect[1] + rect[3]/ 2];
    var endPos = [endRect[0] + endRect[2] / 2, endRect[1] + endRect[3] / 2];

    if (this.timeDrawn < 0.33){
        endPos = [
            startPos[0] + (endPos[0] - startPos[0]) * this.timeDrawn * 3,
            startPos[1] + (endPos[1] - startPos[1]) * this.timeDrawn * 3,
        ]
        this.timeDrawn += lastInterval;
    }

    ctx.strokeStyle = '#0099ff';
    ctx.beginPath();
    ctx.moveTo(startPos[0], startPos[1]);
    ctx.lineTo(endPos[0], endPos[1]);
    ctx.stroke();
};


var duplicatePathExec = function(entity, world){
    var chk = _.any(world.entities, function(worldEntity){
        return worldEntity.pathMoveComponent &&
            ((comparePos(worldEntity.pathMoveComponent.startPosition, entity.pathMoveComponent.startPosition) &&
              comparePos(worldEntity.pathMoveComponent.endPosition, entity.pathMoveComponent.endPosition)) ||
             (comparePos(worldEntity.pathMoveComponent.startPosition, entity.pathMoveComponent.endPosition) &&
              comparePos(worldEntity.pathMoveComponent.endPosition, entity.pathMoveComponent.startPosition)));
            
    });
    if (chk){
        entity.healthComponent.health = 0;
    }
};


var pathButtonRender = function(rect, entity, ui){
    if (!this.pathButtonFunction){
        this.pathButtonFunction = function(){
            ui.world.togglePathBuilding();
        };
    }
    ui.informLine(PARAMETERS.buildPanel, {
        buttonFunction: this.pathButtonFunction,
        text: 'path'
    }, PARAMETERS.baseButtonName);
};


var pathMakerGetReplaceKeys = function(entity, world){
    var start = world.entityForKey(this.startKey);
    var end = world.entityForKey(this.endKey);
    world.connectEntities(start, end);
};


var pathStopRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    if (this.timeDrawn < this.renderTime){
        this.timeDrawn += lastInterval;
        
        var scale = 1;
        if (this.timeDrawn < this.renderTime / 2){
            scale += 0.25 * this.timeDrawn * 2 / this.renderTime;
        }
        else{
            scale += 0.25 * (this.renderTime - this.timeDrawn) * 2 / this.renderTime;
        }
        var newRect = [rect[0] - rect[2] * (scale - 1) / 2, rect[1] - rect[3] * (scale - 1) / 2, rect[2] * scale, rect[3] * scale];
        ctx.drawImage(getImage(this.image), newRect[0], newRect[1], newRect[2], newRect[3]);
    }
    else{
        var image = getImage(this.isActive ? this.activeImage : this.image);
        var x = rect[0] + this.getWobble(lastInterval);

        ctx.drawImage(image, x, rect[1]);

        if (this.outlineImage){
            ctx.drawImage(getImage(this.outlineImage), x, rect[1]);
            this.outlineImage = false;
            
            this.renderTrainIcon(lastInterval, x, rect[1]);
        }
        else{
            if (this.blinkingOutlineImage){
                this.blinkingOutlineTime -= lastInterval;
                if (this.blinkingOutlineTime > 0){
                    ctx.globalAlpha = this.blinkingOutlineTime;
                    ctx.drawImage(getImage(this.blinkingOutlineImage), x, rect[1]);
                    ctx.globalAlpha = 1;
                }
                else{
                    this.blinkingOutlineImage = false;
                }
            }
        }
    }
    this.isActive = false;
};

var renderTrainIcon = function(lastInterval, x, y){
    ctx.fillStyle = this.trainColor;
    ctx.beginPath();
    ctx.arc(x + 30, y + 26, 4, 0, 2 * Math.PI);
    ctx.fill();
};


var getAllPersonality = function(){
    return _.map(this.heldOpinions, getEntityKey).concat(this.personalityTraits);
};

var addOpinionToPersonality = function(opinionKey, entity, world){
    var opinion = makeEcs(opinionKey, {
        personHeld: entity.identityComponent.key
    });
    world.addEntity(opinion);
    this.heldOpinions.push(opinion);
};


var personCreateExec = function(entity, world){
    entity.personalityComponent.heldOpinions = _.map(entity.personalityComponent.heldOpinions, function(opinion){
        opinion = makeEcs(opinion, {
            personHeld: entity.identityComponent.key
        });
        world.addEntity(opinion);
        return opinion;
    });
};


var personKillExec = function(entity, world){
    _.each(entity.personalityComponent.heldOpinions, function(opinion){
        opinion.healthComponent.health = 0;
    });
};


var derivePersonGoalCurrencies = function(currencies, personKey){
    var derivedCurrencies = {};
    _.each(currencies, function(val, key){
        var currencyKey;
        
        if (_.contains(csvIdentifiers.currency, key)){
            currencyKey = key;
        }
        else{
            currencyKey = key + '_' + personKey;
        }

        derivedCurrencies[currencyKey] = val;
    });
    return derivedCurrencies;
};


var addOpinionExec = function(entity, world){
    var person = world.entityForKey(entity.personHeldComponent.personHeld);

    var opinionsToMake = [];
    
    if (this.opinionToAdd){
        opinionsToMake.push(this.opinionToAdd);
    }

    var existingOpinions = [];

    _.each(person.personalityComponent.heldOpinions, function(opinion){
        existingOpinions.push(opinion.identityComponent.key);
        _.each(opinion.opinionComponent.successOpinions, function(val, key){
            if (percentCheck(val)){
                opinionsToMake.push(key);
            }
        });
    });

    _.chain(opinionsToMake)
        .uniq()
        .filter(function(key){
            return !_.contains(existingOpinions, key);
        })
        .each(function(key){
            person.personalityComponent.addOpinionToPersonality(key, person, world);
        });
};


var placedTowerGetReplaceKeys = function(entity, world, args){
    var managedEntities = _.filter(world.entities.concat(world.entitiesToAdd), worldEntity => worldEntity.managedComponent);
    var spaces = _.chain(world.entities)
        .filter(worldEntity => (
            ((worldEntity.identityComponent && worldEntity.identityComponent.key == this.sourceTrait) ||
             (worldEntity.sourceExtensionComponent && worldEntity.sourceExtensionComponent.sourceKey == this.sourceTrait)) &&
                (_.all(managedEntities, managedEntity => !managedEntity.positionComponent.comparePos(worldEntity.positionComponent)))
        ))
        .map(worldEntity => [worldEntity.positionComponent.x, worldEntity.positionComponent.y])
        .value();
    var space = _.min(spaces, pos => Math.abs(pos[0] - this.x) + Math.abs(pos[1] - this.y));
    
    if (space){
        args.x = space[0];
        args.y = space[1];
        args.sourceKey = this.sourceTrait;
        args.sourceTrait = this.sourceTrait;
        return this.tower;
    }
    else{
        return false;
    }
};


var addPoints = function(entity, args){
    entity.pointCounterComponent.points += args.points;
};


var setPos = function(pos){ 
    this.x = pos[0];
    this.y = pos[1]; 
};

var isPos = function(pos){
    return this.x == pos[0] && this.y == pos[1];
};

var compComparePos = function(positionComponent){
    return this.x == positionComponent.x &&
        this.y == positionComponent.y;
};

var assertPosition = function(val, idx){
    if (val !== undefined){
        if (val < 0 || val >= PARAMETERS.size[idx]){
            console.log('impossible position ' + val);
            throw "Impossible position " + val;
        }
    }
    return val;
};

var getAsPos = function(){
    return [this.x, this.y];
};


var printKillExec = function(entity, world){
    console.log(entity);
};


var progressRender = function(rect, entity){
    ctx.fillStyle = '#ffffff';
    var percentComplete = entity.focusPathStopComponent.percentComplete(entity);
    if (percentComplete > 0){
        ctx.fillText('' + percentComplete + '%', rect[0] + this.progressX, rect[1] + this.progressY);
    }
};


var improveQuality = function(entity, world){
    var qualityEntity;
    if (this.qualityEntity){
        qualityEntity = world.entityForKey(this.qualityEntity);
    }
    else{
        qualityEntity = _.filter(world.entities, function(worldEntity){
            return worldEntity.qualityComponent &&
                worldEntity.managedComponent &&
                worldEntity.managedComponent.managerKey == entity.personHeldComponent.personHeld;
        })[0];
    }

    if (this.checkAgainstQuality){
        qualityEntity.qualityComponent.quality += this.qualityDiff;
    }

    if (this.entitiesToMake){
        world.makeEntities(qualityEntity, this.entitiesToMake);
    }
};


var qualityResourceTick = function(entity, world){
    if (this.lastQuality <= this.qualityThreshold && entity.qualityComponent.quality > this.qualityThreshold){
        entity.resourceComponent.resourceKeys = this.highQualityResources;
        world.makeEntities(entity, this.flipEntities);
    }
    else if (this.lastQuality > this.qualityThreshold && entity.qualityComponent.quality <= this.qualityThreshold){
        entity.resourceComponent.resourceKeys = this.lowQualityResources;
        _.each(this.flipEntities, function(flipEntity){
            _.each(world.entitiesForKey(flipEntity), function(worldEntity){
                worldEntity.healthComponent.health = 0;
            });
        });
    }

    this.lastQuality = entity.qualityComponent.quality;
};


var qualityRender = function(rect, entity){
    ctx.fillStyle = '#ffffff';
    ctx.fillText(entity.qualityComponent.quality, rect[0], rect[1] + rect[3])
};


var randomCarouselSetMarker = function(marker){
    var goodCount = marker.randomMenuComponent.goodCount;
    var badCount = marker.randomMenuComponent.badCount;
    
    var badToAdd = 0;
    this.carousel = [];
    for (var i = 0; i < goodCount; i++){
        this.carousel.push(this.goodImage);
        badToAdd += badCount;
        while (badToAdd >= goodCount){
            this.carousel.push(this.badImage);
            badToAdd -= goodCount;
        }
    }
    
    this.goodResult = marker.randomMenuComponent.goodResult;
};

var randomCarouselRender = function(pos, renderTime){
    var finalImage = this.goodResult ? this.goodImage : this.badImage;
    if (this.flatDisplayStartTime){
        if (renderTime > this.flatDisplayStartTime + 1){
            this.animationDone = true;
        }
    }

    var timeToRender = this.flatDisplayStartTime ? this.flatDisplayStartTime : renderTime;
    var index = timeToRender / 0.3;
    var flatIndex = Math.floor(index);
    var fraction = index - flatIndex;
    flatIndex = this.carousel.length - flatIndex;
    while (flatIndex < 0){
        flatIndex += this.carousel.length;
    }
        
    var images = _.map(_.range(4), (i) => {
        var idx = (flatIndex + i) % this.carousel.length;
        return this.carousel[idx];
    });

    if (renderTime > this.animationTime && images[2] == finalImage && !this.flatDisplayStartTime){
        this.flatDisplayStartTime = renderTime;
    }

    var rect = [pos[0], pos[1], this.imgSize[0], this.imgSize[1]];

    
    var sheight = fraction * rect[3];

    ctx.drawImage(getImage(images[0]), 
                  0, rect[3] - sheight, rect[2], sheight,
                  rect[0], rect[1], rect[2], sheight);

    ctx.drawImage(getImage(images[1]), rect[0], rect[1] + sheight);
    ctx.drawImage(getImage(images[2]), rect[0], rect[1] + rect[3] + sheight);
    ctx.drawImage(getImage(images[3]),
                  0, 0, rect[2], rect[3] - sheight,
                  rect[0], rect[1] + 2 * rect[3] + sheight, rect[2], rect[3] - sheight);
    ctx.drawImage(getImage(this.frameImage), rect[0], rect[1]);
};


var randomIfNoneGetReplaceKeys = function(entity, world){
    if (_.all(this.keys, key => !world.entityForKey(key))){
        return _.sample(this.keys);
    }
};


var randomOpenPositionExec = function(entity, world){
    var pos;
    if (entity.managedComponent){
        var allEntities = world.entities.concat(world.entitiesToAdd);
        pos = _.chain(allEntities)
            .filter(function(worldEntity){
                return entity.managedComponent.isManagingEntity(worldEntity) &&
                    !_.any(allEntities, function(chkEntity){
                        return (chkEntity.managedComponent || chkEntity.goalTrackComponent) &&
                            chkEntity.positionComponent.comparePos(worldEntity.positionComponent);
                    });
            })
            .map(function(worldEntity){
                return [worldEntity.positionComponent.x, worldEntity.positionComponent.y];
            })
            .sample()
            .value();
    }
    
    if (!pos){
        if (this.startEntityKey){
            this.startPos = world.findStartPos(this.startEntityKey);
        }
        if (this.startPos && (this.startPos[0] === undefined || this.startPos[1] === undefined)){
            this.startPos = undefined;
        }
        pos = world.randomOpenPosition(entity.positionComponent.planeOfExistence, this.startPos, this.minSelfDist);
    }
    
    entity.positionComponent.setPos(pos);
};


var randomReplaceGetReplaceKeys = function(entity, world){
    var convertEntityGroup = function(entityGroup, entities){
        if (_.isString(entityGroup)){
            entities[entityGroup] = 1;
            return 1;
        }
        else if (_.isArray(entityGroup)){
            _.each(entityGroup, function(entityKey){ entities[entityKey] = 1; });
            return entityGroup.length;
        }
        else{
            _.each(entityGroup, function(val, key){
                entities[key] = val;
            });
            return _.reduce(entityGroup, addFunction, 0);
        }
    };
    
    var entities = {};

    var goodCount = convertEntityGroup(this.goodEntities, entities);
    var badCount = convertEntityGroup(this.badEntities, entities);

    var chanceSum = _.reduce(entities, addFunction, 0);
    var randVal = Math.random() * chanceSum;
    var keys = _.keys(entities);
    var keyToReturn = undefined;
    for (var i = 0; i < keys.length; i++){
        var key = keys[i];
        var chance = entities[key];
        if (chance > randVal){
            keyToReturn = key;
            break;
        }
        else{
            randVal -= chance;
        }
    }

    if (keyToReturn === undefined){
        throw 'random replace failed';
        return false;
    }

    var goodEntities = {};
    convertEntityGroup(this.goodEntities, goodEntities);
    var goodResult = goodEntities[keyToReturn] !== undefined;

    
    if (this.addReplaceMarker){
        world.makeEntities(entity, PARAMETERS.randomMenuMarker, {
            goodCount: goodCount,
            badCount: badCount,
            goodResult: goodResult
        });
    }

    return keyToReturn;
};


var currenciesAtResource = function(entity, world){
    return _.chain(this.resourceKeys)
        .map((resourceKey) =>  _.filter(world.entities, (worldEntity) => (
                worldEntity.identityComponent &&
                worldEntity.identityComponent.sourceId == entity.uid &&
                worldEntity.identityComponent.key == resourceKey &&
                worldEntity.positionComponent.comparePos(entity.positionComponent) &&
                !worldEntity.pathVelocityComponent.isHeld
            )))
        .flatten(true)
        .value();
};


var resourceInteractWithTrain = function(entity, world, train){
    var trainRequirements = train.trainComponent.calculateTrainCurrencies(train, world);

    var currenciesAtResource = entity.resourceComponent.currenciesAtResource(entity, world);

    for (var i = 0; i < entity.resourceComponent.resourceKeys.length; i++){
        var resourceKey = entity.resourceComponent.resourceKeys[i];

        if (trainRequirements[resourceKey] === undefined){
            continue;
        }

        var carriage = train.trainComponent.getCurrentCarriage(train, world);
        var waiting = true;

        _.chain(currenciesAtResource)
            .filter((worldEntity) => !_.contains(carriage.carriageComponent.holding, worldEntity.uid))
            .first(1)
            .each(function(worldEntity){
                carriage.carriageComponent.holding.push(worldEntity.uid);
                worldEntity.pathVelocityComponent.isHeld = true;
                waiting = false;
            });

        return waiting;
    }
    return false;
};

var resourceCurrenciesMadeAtPoint = function(entity){
    return entity.resourceComponent.resourceKeys;
};


var resourceFocusTick = function(entity, world){
    if (entity.resourceComponent.resourceCount !== undefined && entity.resourceComponent.resourceCount <= 0){
        entity.healthComponent.kill()
        return;
    }

    var resourceCountAtPoint = _.filter(world.entities, (worldEntity) => (
        worldEntity.identityComponent &&
            _.contains(entity.resourceComponent.resourceKeys, worldEntity.identityComponent.key) &&
            worldEntity.positionComponent.comparePos(entity.positionComponent)
    )).length;

    if (resourceCountAtPoint < 5){
        world.makeEntities(entity, entity.resourceComponent.resourceKeys, {
            emotionTags: this.emotionTags,
            destination: this.destination,
            firstTick: this.firstTick
        });

        this.firstTick = false;
                
        if (entity.managedComponent){
            entity.managedComponent.addExperienceToManager(entity, world);
        }

        if (entity.resourceComponent.resourceCount){
            entity.resourceComponent.resourceCount -= 1;
        }
        
        world.makeEntities(entity, PARAMETERS.towerFlash);

        if (entity.resourceComponent.resourceEntities){
            world.makeEntities(entity, entity.resourceComponent.resourceEntities);
        }
    }
    else{
        this.focusTickHook(entity, world);
    }
};


var killResourceCurrencies = function(entity, world){
    _.each(entity.resourceComponent.currenciesAtResource(entity, world), 
           function(currencyEntity){
               currencyEntity.healthComponent.kill();
           });
};


var resourceModifierGetTowerForTickModifierRender = function(entity, world){
    return world.entityForUid(entity.resourceModifierComponent.towerId);
};


var revertMemoryExec = function(entity, world){
    var source = world.entityForUid(this.sourceId);
    var sourceTrait = world.entityForKey(source.managedComponent.managerKey);
    var memory = world.transformTrait(sourceTrait.identityComponent.key,
                                      sourceTrait.fadingMemoryComponent.oldTrait, true);
    if (memory){
        _.each(_.range(3), function(){
            memory.memoryComponent.flashbackFunction(memory, world);
        });
    }
};


var risingTextRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    this.currentHeight += this.height * lastInterval / this.effectTime;
    if (this.currentHeight > this.height){
        entity.healthComponent.kill();
    }
    else{
        ctx.fillStyle = '#ffffff';
        ctx.globalAlpha = 1 - 0.5 * (this.currentHeight / this.height);
        ctx.fillText(this.text, this.effectPos[0], this.effectPos[1] - this.currentHeight);
        ctx.globalAlpha = 1;
    }
};


var selfDamageEffectRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    if (this.timeDrawn > this.animationTime){
        entity.healthComponent.kill();
    }

    this.timeDrawn += lastInterval;
    var dist = (this.timeDrawn / (3 * this.animationTime)) + 1;
    dist *= 60;

    ctx.fillStyle = '#ff0000';
    for (var i = 0; i < 3; i++){
        var angle = i * Math.PI / 6;
        var x = dist * Math.cos(angle);
        var y = dist * Math.sin(angle);
        ctx.fillRect(x, y, 2, 2);
    }
};


var selfExtensionSetEmotion = function(emotion){
    this.emotion = emotion;
    this.emotionLife = 30;
};


var selfExtensionRender = function(rect, entity){
    if (entity.selfExtensionComponent.emotion){
        ctx.fillStyle = EMOTION_FILLSTYLES[entity.selfExtensionComponent.emotion];
    }
    else {
        ctx.fillStyle = '#ffffff';
    }

    ctx.fillRect(rect[0] + 10, rect[1] + 10, 20, 20);
};


var selfExtensionTick = function(entity){
    if (entity.selfExtensionComponent.emotionLife){
        entity.selfExtensionComponent.emotionLife -= 1;
        if (entity.selfExtensionComponent.emotionLife <= 0){
            entity.selfExtensionComponent.emotion = undefined;
        }
    }
};


var setFlagExec = function(entity, world){
    world.flags[this.flag] = this.flagValue;
};


var settingsPanelRender = function(rect, entity, ui){
    var panelButtons = [];
    var that = this;

    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);
    
    ctx.fillStyle = '#000000';
    ctx.font = getFont(40);
    ctx.fillText('OPTIONS', rect[0] + rect[2] / 2 - ctx.measureText('OPTIONS').width / 2, 45);
    ctx.font = BASE_FONT;
    
    ctx.fillText('FULLSCREEN', rect[0] + 10, rect[1] + 85);

    var insetColor = (p) => p ? '#ff0000' : '#000000';

    var fullscreenRect = [rect[0] + 100, rect[1] + 70, 100, 30];

    if (!this.fullscreenFunction){
        this.fullscreenFunction = function(){
            if (ui.gameProperties.settings.fullscreen){
                document.webkitExitFullscreen();
            }
            else{
                canvas.webkitRequestFullscreen();
            }
            ui.gameProperties.settings.fullscreen = !ui.gameProperties.settings.fullscreen;
            ui.gameProperties.save();
        };
    }

    this.drawPanelButton(fullscreenRect, 'Toggle');
    panelButtons.push([fullscreenRect, this.fullscreenFunction]);

    ctx.fillText('SOUND', rect[0] + 10, rect[1] + 135);
    var soundRect = [rect[0] + 100, rect[1] + 120, 40, 40];

    if (!this.soundFunction){
        this.soundFunction = function(){
            if (ui.gameProperties.settings.music){
                ui.gameProperties.backgroundAudio.pause();
            }
            else{
                ui.gameProperties.backgroundAudio.play();
            }

            ui.gameProperties.settings.music = !ui.gameProperties.settings.music;
            ui.gameProperties.save();
        };
    }

    var soundVols = [0.05, 0.1, 0.2];
    if (!this.soundVolFunctions || this.soundVolFunctions.length === 0){
        this.soundVolFunctions = _.map(soundVols, function(vol){
            return function(){
                ui.gameProperties.settings.musicVolume = vol;
                ui.gameProperties.backgroundAudio.volume = vol;

                if (!ui.gameProperties.settings.music){
                    ui.gameProperties.settings.music = true;
                    ui.gameProperties.backgroundAudio.play();
                }

                ui.gameProperties.save();
            };
        });
    }

    this.insetColor = insetColor(!ui.gameProperties.settings.music);
    this.drawImageButton(soundRect, 'mute');
    panelButtons.push([soundRect, this.soundFunction]);
    
    _.each(this.soundVolFunctions, function(volFunction, i){
        var iRect = [soundRect[0] + 60 * (i + 1), soundRect[1], soundRect[2], soundRect[3]];
        that.insetColor = insetColor(ui.gameProperties.settings.music && ui.gameProperties.musicVolume == soundVols[i]);
        that.drawImageButton(iRect, 'sound' + i);
        panelButtons.push([iRect, volFunction]);
        that.insetColor = '#000000'
    });

    ctx.fillText('SFX', rect[0] + 10, rect[1] + 185);
    var sfxRect = [rect[0] + 100, rect[1] + 170, 40, 40];
    
    if (!this.sfxFunction){
        this.sfxFunction = function(){
            ui.gameProperties.settings.sfx = !ui.gameProperties.settings.sfx;
            ui.gameProperties.save();
        }
    }

    var sfxVols = [0.25, 0.5, 0.75];
    if (!this.sfxVolFunctions || this.sfxVolFunctions.length === 0){
        this.sfxVolFunctions = _.map(sfxVols, function(vol){
            return function(){
                getAudio.changeVol(vol);
                ui.gameProperties.settings.soundVolume = vol;
                ui.gameProperties.settings.sfx = true;
                ui.gameProperties.save();
            };
        })
    }

    this.insetColor = insetColor(!ui.gameProperties.settings.sfx);
    this.drawImageButton(sfxRect, 'mute')
    panelButtons.push([sfxRect, this.sfxFunction]);
    
    _.each(this.sfxVolFunctions, function(volFunction, i){
        var iRect = [sfxRect[0] + 60 * (i + 1), sfxRect[1], sfxRect[2], sfxRect[3]];
        that.insetColor = insetColor(ui.gameProperties.settings.sfx && ui.gameProperties.settings.soundVolume == sfxVols[i]);
        that.drawImageButton(iRect, 'sound' + i);
        that.insetColor = '#000000';
        panelButtons.push([iRect, volFunction]);
    });

    var difficultySetting = ui.world.entityForKey(PARAMETERS.difficultySetting);

    if (!this.difficultyFunctions || this.difficultyFunctions.length === 0){
        this.difficultyFunctions = _.map(_.range(4), function(i){
            return function(){
                difficultySetting.difficultySettingComponent.difficulty = i;
            }
        })
    }

    ctx.fillText('DIFFICULTY', rect[0] + 10, rect[1] + 235)
    _.each(this.difficultyFunctions, (difficultyFunction, i) => {
        var displayIdx = this.difficultyFunctions.length - i;
        var iRect = [rect[0] + 50 + 50 * displayIdx, rect[1] + 220, 40, 40];
        this.insetColor = insetColor(difficultySetting.difficultySettingComponent.difficulty == i);
        this.drawPanelButton(iRect, '' + displayIdx);
        this.insetColor = '#000000';
        panelButtons.push([iRect, difficultyFunction]);
    });

    if (!this.quitFunction){
        this.quitFunction = function(){
            nw.App.quit();
        };
    }

    var quitRect = [rect[0] + 100, rect[1] + 270, 100, 30];
    this.drawPanelButton(quitRect, 'Quit');
    panelButtons.push([quitRect, this.quitFunction]);

    return panelButtons;
};


var singleUseMakeTrain = function(entity, world){
    if (this.trainsToMake > 0){
        this.trainsToMake -= 1;
        return this.baseMakeTrain(entity, world);
    }
    else{
        entity.healthComponent.kill()
        return undefined;
    }
};


var sourceCurrenciesNeededAtPoint = function(){
    return csvIdentifiers.creep;
};


var creepAccept = function(entity, world, creep){
    entity.healthComponent.health -= creep.creepComponent.selfDamage;
    world.makeEntities(creep, this.creepHitEntities, {
        emotion: creep.creepComponent.emotion
    })
};


var focusEfficiency = function(){
    return 1 - (this.focusUsing / (this.focusCount + 2));
};


var sourceExtensionOnClick = function(entity, world, ui){
    var source = world.entityForKey(entity.sourceExtensionComponent.sourceKey);
    source.clickComponent.onClick(source, world, ui);
};


var sourceExtensionRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    if (_.isArray(this.image)){
        this.image = _.sample(this.image);
    }
    var world = ui.world;
    var source = world.entityForKey(entity.sourceExtensionComponent.sourceKey);
    var image = getImage(source.entityManagerComponent.disabled ? this.disabledImage : this.image);

    var xDiff = this.getWobble(lastInterval);
    var x = rect[0] + xDiff;

    ctx.drawImage(image, x, rect[1]);

    var button = world.currentMakingEntity;
    if (button){
        if (button.buttonControlComponent.checkMakePos(world, entity.positionComponent.getAsPos())){
            ctx.drawImage(getImage(this.outlineImage), x, rect[1]);
        }
    }

    if (source.entityManagerComponent.hasNew){
        this.timeToBlink -= lastInterval;
        if (this.timeToBlink > 0){
            ctx.drawImage(getImage(this.newImage), x, rect[1]);
        }
        else if (this.timeToBlink < -0.1){
            this.timeToBlink += 1;
        }
    }
};


var checkParticleEffectAlive = function(entity, world){
    return world.entityForUid(this.sourceId) !== undefined;
};


var spellRender = function(rect, entity, ui){
    if (entity.spellComponent.spellButtonFunction === undefined){
        entity.spellComponent.spellButtonFunction = makeWrappedSpellFunction(entity, ui.world);
    }
    ui.addLine('#spells', {
        line: [
            {
                buttonFunction: entity.spellComponent.spellButtonFunction,
                text: entity.identityComponent.name
            },
            dictString(entity.spellComponent.spellCost)
        ]
    });
};

var makeWrappedSpellFunction = function(entity, world){
    return function(){
        if (world.player.calculatedCurrencyComponent.satisfiesCurrencyReq(entity.spellComponent.spellCost)){
            world.currentSpell = entity;
        }
    };
};


var starParticleEffectRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    if (this.timeDrawn > this.scaleTime){
        entity.healthComponent.kill();
    }

    this.timeDrawn += lastInterval;
    var dist = (this.timeDrawn / (3 * this.scaleTime)) + 1;
    var image = getImage(this.image);

    for (var i = 8; i < 11; i++){
        var angle = i * Math.PI / 6;
        var x = 60 * dist * Math.cos(angle);
        var y = 60 * dist * Math.sin(angle);
        ctx.drawImage(image, this.effectPos[0] + x, this.effectPos[1] + y);
    }
};


var checkSteamAchievement = function(entity, args){
    if (args.key == entity.steamAchievementComponent.keyToCheck){
        console.log('Completed achievement: ' + entity.steamAchievementComponent.steamAchievementKey);
        if (STEAM){
            greenworks.activateAchievement(entity.steamAchievementComponent.steamAchievementKey, trueFunction);
        }
    }
};


var swallowOpinionCreate = function(entity, world){
    entity.swallowOpinionComponent.previousOpinions = _.chain(world.entities)
        .filter((worldEntity) => {
            return (worldEntity.opinionComponent &&
                    worldEntity.personHeldComponent.personHeld == entity.personHeldComponent.personHeld &&
                    worldEntity.identityComponent.key != entity.identityComponent.key &&
                    !_.contains(this.swallowExceptions, worldEntity.identityComponent.key));
        })
        .map(function(worldEntity){
            worldEntity.healthComponent.kill();
            return worldEntity.identityComponent.key;
        })
        .value();
};


var killPersonGoals = function(entity, world){
    _.chain(world.entities)
        .filter(function(worldEntity){ 
            return worldEntity.personHeldComponent &&
                worldEntity.worldGoalComponent;
        })
        .each(function(worldEntity){
            worldEntity.healthComponent.kill();
        });
};


var swallowOpinionKill = function(entity, world){
    world.makeEntities(entity, entity.swallowOpinionComponent.previousOpinions);
};


var checkTickContinue = function(world, entity){
    return !(this.currency.will && 
             this.currency.will < 0 && 
             world.player.calculatedCurrencyComponent.currencies.will < 0);
};


var timedDeathRender = function(rect, entity){
    if (entity.timedDeathComponent){
        ctx.fillStyle = '#ffffff';
        var timeLeft = Math.floor(entity.timedDeathComponent.timeToDeath / PARAMETERS.ticksPerTick[0]);
        ctx.fillText('' + timeLeft, rect[0] + rect[2] / 2 - 15, rect[1] + rect[3] - 2);
    }
};


var timedDifficultyModify = function(entity, world){
    var difficulty = world.entityForKey(PARAMETERS.difficultySetting).difficultySettingComponent.difficulty;
    entity.timedDeathComponent.timeToDeath += Math.floor(difficulty * entity.timedDeathComponent.timeToDeath / 3);
};


var timedMakeEntities = function(entity, world){
    if (entity.timedDeathComponent && entity.timedDeathComponent.timeToDeath <= 0){
        world.makeEntities(entity, this.timedOutEntities);
    }
};


var timedRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    if (this.timeDrawn < this.renderTime){
        this.timeDrawn += lastInterval;
        this.renderWhileTimed(rect, entity, ui, rectCount, timeToNextTick, lastInterval);
    }
    else{
        var idx = entity.rendererComponents.indexOf(this);
        if (this.nextRenderComponent){
            entity.rendererComponents[idx] = this.nextRenderComponent;
        }
        else{
            entity.rendererComponents.splice(idx, 1);
        }
    }
};


var timedScaleRenderWhenTimed = function(rect, entity){
    var img = getImage(this.image);
    var scale = 1 + 0.5 * (this.renderTime - this.timeDrawn) / this.renderTime;
    var newRect = [rect[0] - rect[2] * (scale - 1) / 2, rect[1] - rect[3] * (scale - 1) / 2, rect[2] * scale, rect[3] * scale];
    ctx.drawImage(img, newRect[0], newRect[1], newRect[2], newRect[3]);
};


var toastRender = function(rect, entity, ui, rectCount, timeToNextTick){
    ctx.fillStyle = '#ff0000';
    ctx.beginPath();
    ctx.arc(rect[0], rect[1], 5, 0, 2 * Math.PI);
    ctx.fill();
};


var toastClick = function(entity, world, ui){
    ui.openPanelAtPos(this.panelKey, entity.positionComponent);
    entity.healthComponent.health = 0;
};


var toastNotification = function(entity, args){
    if (args.key == entity.clickComponent.panelKey){
        entity.healthComponent.health = 0;
    }
};


var damageRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    if (entity.damageComponent){
        if (entity.damageComponent.ticks <= 0){
            ctx.fillStyle = '#ffffff';
        }
        else{
            ctx.fillStyle = '#ffff00';
            var cooldownImage = getImage('cooldown' + min(entity.damageComponent.ticks, 2));
            ctx.drawImage(cooldownImage, rect[0], rect[1]);
        }

        if (entity.damageComponent.charges === 0){
            this.blinkTimer += lastInterval
        }
        else{
            this.blinkTimer = 0;
        }

        if (this.blinkTimer < 1.8){
            var i;

            var width = (entity.damageComponent.maxCharges == 5) ? 4 : 6;

            for (i = 0; i < entity.damageComponent.charges; i++){
                ctx.fillRect(rect[0] + 17 + (width * 2 - 2) * i, rect[1] + rect[3] - 12, width, 10);
            }
            
            ctx.fillStyle = '#aaaaaa';
            for (; i < entity.damageComponent.maxCharges; i++){
                ctx.fillRect(rect[0] + 17 + (width * 2 - 2) * i, rect[1] + rect[3] - 12, width, 10);
            }
        }
        else if (this.blinkTimer > 2){
            this.blinkTimer -= 2;
        }
    }
};


var towerTick = function(entity){
    _.each(entity.rendererComponents, function(renderComponent){
        if (renderComponent.activated > 0){
            renderComponent.activated -= 1;
        }
    });
        
    this.timeToAttrition -= 1;

    if (this.timeToAttrition <= 0){
        this.timeToAttrition = PARAMETERS.dayTicks;
        if (this.damageComponent){
            this.damageComponent.charges -= 1;
            if (this.damageComponent.charges < 0){
                this.damageComponent.charges = 0;
            }
        }
    }
};


var currencyActionForTower = function(entity, world){
    return _.chain(world.entities)
        .filter(function(chkEntity){
            return chkEntity.currencyActionComponent && 
                _.contains(chkEntity.currencyActionComponent.towerIds, entity.uid);
        })
        .first()
        .value();
};

var possibleCurrencyActionForTower = function(entity, world){
    return _.chain(world.entities)
        .filter(function(chkEntity){
            return chkEntity.currencyActionComponent &&
                chkEntity.currencyActionComponent.towerKey == entity.identityComponent.key;
        })
        .first()
        .value();
};

var canDamageTower = function(entity){
    return entity.damageComponent === undefined;
};


var towerCreateExec = function(entity, world){
    _.chain(world.entities)
        .filter(function(worldEntity){
            return worldEntity.currencyActionComponent &&
                worldEntity.currencyActionComponent.towerKey == entity.identityComponent.key &&
                worldEntity.currencyActionComponent.towerIds.length > 0;
        })
        .each(function(worldEntity){
            worldEntity.currencyActionComponent.nextIds.push(entity.identityComponent.uid);
        });
};


var towerCurrenciesNeededAtPoint = function(entity, world){
    var currencyAction = entity.towerComponent.possibleCurrencyActionForTower(entity, world);

    return currencyAction ? currencyAction.currencyActionComponent.currenciesRequired : [];
};

var towerCurrenciesMadeAtPoint = function(entity, world){
    var currencyAction = entity.towerComponent.possibleCurrencyActionForTower(entity, world);

    return currencyAction ? currencyAction.currencyActionComponent.currenciesToMake : [];
};

var towerInteractWithTrain = function(entity, world, train){
    var currencyAction = entity.towerComponent.possibleCurrencyActionForTower(entity, world);
    var trainPath = world.entityForUid(train.trainVelocityComponent.trainPath);

    if (!currencyAction){
        train.healthComponent.kill();
        if (trainPath){
            trainPath.healthComponent.kill();
        }
        return false;
    }

    var entitiesToLoad = [];

    var currenciesNeeded = train.trainComponent.calculateTrainCurrencies(train, world, 1);

    var isLoading = _.any(this.currenciesMadeAtPoint(entity, world), function(currencyKey){
        return currenciesNeeded[currencyKey] && (currenciesNeeded[currencyKey] > 0);
    });

    if (isLoading && this.currenciesExistAtPoint(entity, world)){
        var currenciesMadeAtPoint = _.countBy(this.currenciesMadeAtPoint(entity, world), _.identity);

        var currenciesAtPoint = _.filter(world.entities, function(worldEntity){
            return worldEntity.pathVelocityComponent &&
                worldEntity.positionComponent.comparePos(entity.positionComponent);
        });

        entitiesToLoad = _.filter(currenciesAtPoint, function(currency){
            var key = currency.identityComponent.key;
            if (currenciesMadeAtPoint[key] && currenciesMadeAtPoint[key] > 0){
                currenciesMadeAtPoint[key] -= 1;
                return true;
            }
            return false;
        });
    }
    else{
        if (entity.focusTickResponseComponent.isReady || entity.damageComponent){
            var currenciesToConsume = this.currenciesNeededAtPoint(entity, world);

            var currencyCounts = _.countBy(currenciesToConsume, _.identity);
            
            
            var carriage = train.trainComponent.getCurrentCarriage(train, world);
            carriage.carriageComponent.holding = _.filter(carriage.carriageComponent.holding, function(holdId){
                var holdItem = world.entityForUid(holdId);
                if (!holdItem){
                    return false;
                }
                if (currencyCounts[holdItem.identityComponent.key] > 0){
                    currencyCounts[holdItem.identityComponent.key] -= 1;
                    holdItem.healthComponent.kill();
                    return false;
                }
                return true;
            });
            

            currencyAction = entity.towerComponent.currencyActionForTower(entity, world);
            
            if (!currencyAction){
                train.healthComponent.kill();
                var trainPath = world.entityForUid(train.trainVelocityComponent.trainPath);
                if (trainPath){
                    trainPath.healthComponent.kill();
                }
                return false;
            }
            
            entitiesToLoad = world.makeEntities(entity, currencyAction.currencyActionComponent.currenciesToMake);
            if (currencyAction.currencyActionComponent.entitiesOnConvert){
                world.makeEntities(entity, currencyAction.currencyActionComponent.entitiesOnConvert);
            }
                        
            
            if (entity.damageComponent && entity.damageComponent.charges < entity.damageComponent.maxCharges){
                entity.damageComponent.charges += 1;
                if (entity.damageComponent.charges >= entity.damageComponent.maxCharges){
                    trainPath.healthComponent.kill();
                    train.healthComponent.kill();
                }
            }

            _.each(this.convertExecutables, function(convertExecutable){
                convertExecutable.execute(entity, world);
            });

            var rect =  world.hexMap.cellForPosComp(entity.positionComponent).rect;
            world.makeEntities(entity, this.risingTextKey, {
                text: currencyAction.identityComponent.name,
                effectPos: [rect[0], rect[1]]
            })
            
            entity.focusTickResponseComponent.isReady = false;
        }
        else{
            entity.focusTickResponseComponent.isWaiting = true;
            return true;
        }
    }
    
    if (entitiesToLoad.length > 0){
        var carriage = train.trainComponent.getCurrentCarriage(train, world);
        _.each(entitiesToLoad, function(entityToLoad){
            carriage.carriageComponent.holding.push(getUid(entityToLoad));
        });
    }

    entity.managedComponent.addExperienceToManager(entity, world);

    return false;
};


var towerFocusTick = function(entity, world){
    if (this.isWaiting){
        this.isReady = true;
        this.isWaiting = false;
        world.makeEntities(entity, PARAMETERS.towerFlash);
    }
};


var canBuildTower = function(world){
    var managingEntity = world.entityForKey(this.managerKey);
    
    if (!managingEntity){
        return false;
    }

    if (!managingEntity.entityManagerComponent.canMakeManagedEntity(managingEntity, world)){
        return false;
    }

    var existingTowerCount = _.reduce(this.limitingKeys, function(memo, val){
        var existingTowers = world.entitiesForKey(val);
        existingTowers = _.filter(existingTowers, 
                                  existingTower => _.intersection(existingTower.interactionComponent.interactionKeys, 
                                                                  managingEntity.interactionComponent.interactionKeys).length > 0);
        return memo + existingTowers.length;
    }, 0);

    if (existingTowerCount >= this.maxTowerCount){
        return false;
    }

    return true;
};

var buildTower = function(world, pos, entity, interactionKey){
    entity.buttonControlComponent.isNew = false;
    var manager = world.entityForKey(this.managerKey);
    if (manager){
        manager.entityManagerComponent.checkForNewManaged(manager, world);
    }
    
    var args = {
        x: pos[0],
        y: pos[1],
        sourceKey: this.managerKey,
        sourceTrait: this.managerKey
    };
    if (interactionKey){
        args.interactionKeys = [interactionKey];
    }

    var entity = makeEcs(this.constructionKey, args);

    return entity;
};

var checkTowerMakePos = function(world, pos){
    var that = this;
    var isManagedPos = _.any(world.entities, function(entity){
        return (entity.identityComponent && entity.identityComponent.key == that.managerKey ||
                (entity.sourceExtensionComponent && entity.sourceExtensionComponent.sourceKey == that.managerKey)) &&
            entity.positionComponent.isPos(pos);
    });

    var isFreePos = !_.any(world.entities, function(entity){
        return entity.managedComponent && entity.positionComponent.isPos(pos);
    });
    
    return isManagedPos && isFreePos;
};


var killTowerButtonExec = function(entity, world){
    if (this.killTowersOnDeath){
        _.each(world.entitiesForKey(entity.buttonControlComponent.entityKey), function(tower){
            tower.healthComponent.health = 0;
        });
    }
};


var towerFlashRender = function(rect, entity, ui, rectCount, timeToDeath, lastInterval){
    if (this.timeToDeath <= 0){
        entity.healthComponent.kill();
    }
    else{
        var imageIndex = Math.floor(this.timeToDeath / 0.167);
        var image = getImage(this.images[imageIndex]);
        ctx.drawImage(image, rect[0], rect[1]);
        
        this.timeToDeath -= lastInterval;
    }
};


var getTowerForTickModifierRender = function(entity, world){
    return world.entityForUid(entity.tickModifyComponent.towerId);
};

var towerTickModifierRender = function(rect, entity, ui){
    var tower = this.getTowerForTickModifierRender(entity, ui.world);
    if (!tower){
        return;
    }

    var rect = ui.world.hexMap.cellForPosComp(tower.positionComponent).rect;
    ctx.drawImage(getImage(this.image), rect[0] + rect[2] / 2, rect[1] + rect[3] / 2);
};


var calculateTrainCurrencies = function(entity, world, offset){
    var trainPath = world.entityForUid(entity.trainVelocityComponent.trainPath);
    if (!trainPath){
        return {};
    }
    var currencies = [];
    offset = offset ? offset : 0;
    var startIndex = entity.trainVelocityComponent.stopIndex + offset;
    for (var i = startIndex; i < trainPath.trainPathComponent.trainStops.length; i++){
        var trainStop = trainPath.trainPathComponent.trainStops[i];
        var stop = world.entityForUid(trainStop);
        if (stop){
            currencies = currencies.concat(stop.focusPathStopComponent.currenciesNeededAtPoint(stop, world));
        }
    }
    
    return _.countBy(currencies, _.identity);
};

var getCurrentCarriage = function(entity, world){
    return world.entityForUid(this.carriage);
};

var getCurrenciesHeld = function(entity, world){
    var carriage = world.entityForUid(this.carriage);

    return _.chain(carriage.carriageComponent.holding)
        .map(function(currencyId){ return world.entityForUid(currencyId); })
        .filter(_.identity)
        .value();
};


var trainCreateExec = function(entity, world){
    var startEntity = world.entityForUid(this.trainStartId);

    if (!startEntity){
        entity.healthComponent.health = 0;
        return;
    }

    entity.positionComponent.x = startEntity.positionComponent.x;
    entity.positionComponent.y = startEntity.positionComponent.y;
    
    var trainPath = world.entityForUid(this.trainPath);
    var start = [entity.positionComponent.x, entity.positionComponent.y];


    var stops = _.map(trainPath.trainPathComponent.trainStops, path => _.clone(path));
    entity.trainVelocityComponent.trainStops = stops;
    
    entity.trainVelocityComponent.currentPath = entity.trainVelocityComponent.allPaths[0];
    
    var carriage = world.makeEntities(entity, this.carriageKey, {
        x: entity.positionComponent.x,
        y: entity.positionComponent.y,
    })[0];
                
    entity.trainComponent.carriage = carriage.uid;

    var existingCarriages = _.filter(world.entities, worldEntity => worldEntity.carriageComponent);

    _.each(entity.trainComponent.calculateTrainCurrencies(entity, world), function(val, key){
        var startCurrency = _.chain(world.entities)
            .filter(function(entity){
                return entity.identityComponent && 
                    entity.identityComponent.key == key &&
                    entity.positionComponent.comparePos(startEntity.positionComponent) &&
                    !_.any(existingCarriages, carriage => _.contains(carriage.carriageComponent.holding, entity.uid));
            })
            .first()
            .value();

        if (startCurrency){
            carriage.carriageComponent.holding.push(startCurrency.uid);
        }
    });
};


var trainKillExec = function(entity, world){
    var carriage = world.entityForUid(entity.trainComponent.carriage);
        
    carriage.healthComponent.kill();

    _.chain(carriage.carriageComponent.holding)
        .map(function(holdingId){ return world.entityForUid(holdingId); })
        .each(function(currency){
            if (currency){
                currency.healthComponent.health = 0;
            }
        });
};


var trainRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    var dx = 15;
    var dy = 15;
    
    if (ui.game.tickSystemWrapper.running){
        var subfraction = 1 - (timeToNextTick * ui.game.ticksPerTick * TICKS_PER_SECOND);
        var fraction = (ui.game.tickSystemWrapper.ticks + subfraction) / 10;

        if (ui.world.lostControl()){
            fraction = 0;
        }
        
        var nextPos = entity.trainVelocityComponent.currentPath[0];
        var drawPos = [rect[0], rect[1]];
        if (nextPos){
            nextPos = ui.world.hexMap.hexMap[nextPos[0]][nextPos[1]].rect;
            drawPos = [drawPos[0] + (nextPos[0] - drawPos[0]) * fraction, 
                       drawPos[1] + (nextPos[1] - drawPos[1]) * fraction];
        }

        _.each(entity.trainComponent.getCurrenciesHeld(entity, ui.world), function(currency, i){
            _.each(currency.rendererComponents, function(renderComponent){
                renderComponent.renderPos = [drawPos[0] + rect[2] / 2 - 8,
                                             drawPos[1] + rect[3] / 2 - 8 + i * 10];
            });
        });
        
        drawPos = [drawPos[0] + rect[2] / 2 - dx, drawPos[1] + rect[3] / 2 - dy];
        drawPos = [Math.floor(drawPos[0]), Math.floor(drawPos[1])];
        
        this.timeDrawn += lastInterval;
        var chkPreviousPos = (pos) => (!_.any(this.previousPositions, (prevPos) => comparePos(prevPos, pos)));
        if (this.timeDrawn > 0.1){
            if (chkPreviousPos(drawPos)){
                this.previousPositions.push(drawPos);
            }
            else{
                var nextPos = [drawPos[0], drawPos[1] - 10];
                if (!chkPreviousPos(nextPos)){
                    nextPos = [drawPos[0] - 10, drawPos[1] + 10];
                    if (!chkPreviousPos(nextPos)){
                        nextPos = [drawPos[0] + 10, drawPos[1] + 10];
                    }
                }
                this.previousPositions.push(nextPos);
            }
            this.linePos = drawPos;
            this.previousPositions = _.last(this.previousPositions, 3);
            
            this.timeDrawn = 0;
        }
    }
        
    ctx.fillStyle = '#ede9e6';
    ctx.strokeStyle = this.trainColor;
    
    _.each(this.previousPositions, function(prevPos){
        ctx.beginPath();
        ctx.arc(prevPos[0] + 15, prevPos[1] + 15, 3, 0, 2 * Math.PI);
        ctx.fill();
        
        ctx.beginPath();
        ctx.arc(prevPos[0] + 15, prevPos[1] + 15, 4, 0, 2 * Math.PI);
        ctx.stroke();
    });
};


var trainPanelRender = function(rect, entity, ui){
    var panelButtons = [];

    var world = ui.world;
    var path = world.entityForUid(entity.panelComponent.sourceId);
    
    if (!path){
        entity.panelComponent.closed = true;
    }
    else if (entity.panelComponent.minimized){
        entity.panelComponent.closed = true;
    }
    else {
        entity.absolutePositionComponent.size[1] = 350 + path.trainPathComponent.trainStops.length * 60;
        rect = entity.absolutePositionComponent.getAbsPosRect();
        
        ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);

        ctx.fillStyle = this.textColor;
        ctx.font = getFont(28);

        var header = 'Train';

        var width = ctx.measureText(header).width;
        ctx.fillText(header, rect[0] + (rect[2] - width) / 2, rect[1] + 60);

        panelButtons.push(this.drawHelpButton(entity, rect));

        ctx.font = getFont(20);
        ctx.fillSyle = this.textColor;
        var y;
        _.each(path.trainPathComponent.trainStops, (stopId, i) => {
            if (i !== 0){
                ctx.drawImage(getImage(this.arrowImage), rect[0] + 120, y + 10);
            }

            y = rect[1] + 100 + (i + 1) * 60;

            var stop = world.entityForUid(stopId);

            if (!stop){
                return;
            }

            if (stop.uiDataComponent){
                stop.uiDataComponent.drawImage(stop, world, [rect[0] + 30, y - 30]);
            }
            else if (stop.identityComponent && stop.identityComponent.image){
                ctx.drawImage(getImage(stop.identityComponent.image), rect[0] + 30, y - 30);
            }
            
            ctx.fillText(stop.identityComponent.name, rect[0] + 100, y);
        });

        ctx.font = getFont(18);
        var buttonWidth = 200;

        if (!path.trainPathComponent.canMakeTrain(path, world) && PARAMETERS.buildablePaths){
            var connectRect = [rect[0] + (rect[2] - buttonWidth) / 2, y + 40, buttonWidth, 40];
            this.drawPanelButton(connectRect, 'CONNECT TRACK');
            panelButtons.push([connectRect, trainPanelStartTrack]);
        }
        else if (this.isConnectingTrack){
            entity.panelComponent.closed = true;
        }

        var killPathRect = [rect[0] + (rect[2] - buttonWidth) / 2, y + 100, buttonWidth, 40];
        this.drawPanelButton(killPathRect, 'STOP TRAIN');
        panelButtons.push([killPathRect, path.trainPathComponent.getKillTrainPath(path, world)]);

        ctx.font = BASE_FONT;
    }
    return panelButtons;
};

var trainPanelStartTrack = function(entity, ui){
    entity.rendererComponents[0].isConnectingTrack = true;
    entityPanelStartTrack(entity, ui);
};


var makeTrain = function(entity, world){
    if (this.allPaths.length === 0){
        var startEntity = world.entityForUid(this.trainStartId);

        if (!startEntity){
            entity.healthComponent.kill();
            return;
        }
        
        var start = [startEntity.positionComponent.x, startEntity.positionComponent.y];

        var paths = _.filter(world.entities, function(worldEntity){
            return worldEntity.pathMoveComponent;
        });

        _.each(this.trainStops, (stopId) => {
            var stop = world.entityForUid(stopId);
            stop = [stop.positionComponent.x, stop.positionComponent.y];
            var path = world.ensurePath(start, stop, paths);
            this.allPaths.push(path);
            start = stop;
        });
    }

    var train = makeEcs(this.trainKey, {
        trainPath: entity.uid,
        trainStartId: this.trainStartId,
        trainColor: this.trainColor,
        allPaths: _.map(this.allPaths, path => _.clone(path))
    });
    entity.trainPathComponent.trainId = train.uid;
    world.addEntity(train);
    return train;
};

var canMakeTrain = function(entity, world){
    if (this.requiresFullPath){
        var paths = world.getAllPaths();
        
        var stops = [this.trainStartId].concat(this.trainStops);
        
        stops = _.map(stops, function(stopId){ return world.entityForUid(stopId); });
        
        if (_.any(stops, function(stop){ return stop === undefined; })){
            return false;
        }

        var getPosition = function(entity){
            return [entity.positionComponent.x, entity.positionComponent.y];
        };
        for (var i = 0; i < stops.length - 1; i++){
            var start = getPosition(stops[i]);
            var stop = getPosition(stops[i + 1]);
            if (determinePath(start, stop, paths) === undefined){
                return false;
            }
        }
    }
    return true;
};

var getKillTrainPath = function(entity, world){
    if (this.killTrainPath === undefined){
        this.killTrainPath = function(){
            entity.healthComponent.kill();
            _.chain(world.entities)
                .filter(function(worldEntity){
                    return worldEntity.trainVelocityComponent &&
                        worldEntity.trainVelocityComponent.trainPath == entity.uid;
                })
                .each(function(worldEntity){
                    worldEntity.healthComponent.kill();
                });
        };
    }
    return this.killTrainPath;
};


var trainPathWarningRender = function(rect, entity, ui){
    var world = ui.world;

    if (!entity.trainPathComponent.canMakeTrain(entity, world)){
        var lastStop = world.entityForUid(_.last(entity.trainPathComponent.trainStops));
        
        if (!lastStop){
            return;
        }

        var lastStopRect = world.hexMap.cellForPosComp(lastStop.positionComponent).rect;
        ctx.fillStyle = '#ffff00';
        ctx.fillRect(lastStopRect[0] + lastStopRect[2] - 10, lastStopRect[1] + lastStopRect[3], 10, 10);
    }
};


var trainPathRenderWrapper = function(entity, world, fn){
    _.each(entity.trainPathComponent.trainStops, function(stopId){
        var trainStop = world.entityForUid(stopId);
        if (!trainStop){
            return;
        }

        fn(trainStop)
    });
};

var trainPathTowerActiveRender = function(rect, entity, ui){
    trainPathRenderWrapper(entity, ui.world, (trainStop) => {
        if (trainStop.rendererComponents[0].activeImage){
            trainStop.rendererComponents[0].isActive = true;
        }
    });
};


var trainPathSecondRender = function(rect, entity, ui){
    trainPathRenderWrapper(entity, ui.world, (trainStop) => {
        trainStop.rendererComponents[0].outlineImage = this.image;
        trainStop.rendererComponents[0].trainColor = entity.trainPathComponent.trainColor;
    });
};


var trainPathMenuCloseExec = function(entity, world){
    if (!PARAMETERS.buildablePaths && !entity.trainPathComponent.canMakeTrain(entity, world)){
        entity.healthComponent.kill();
        var lastStop = _.last(entity.trainPathComponent.trainStops);
        lastStop = world.entityForUid(lastStop);
        if (lastStop.constructionComponent && !lastStop.constructionComponent.ticked){
            lastStop.healthComponent.kill();
        }
    }
};


var blinkTrainStopsExec = function(entity, world){
    trainPathRenderWrapper(entity, world, (trainStop) => {
        var renderComponent = trainStop.rendererComponents[0];
        renderComponent.blinkingOutlineImage = this.image;
        renderComponent.blinkingOutlineTime = 1;
    });
};


var setTrainColorExec = function(entity, world){
    var existingPathColors = _.chain(world.entities)
        .filter(worldEntity => (worldEntity.trainPathComponent &&
                                worldEntity.trainPathComponent.stoppable &&
                                _.isEqual(worldEntity.interactionComponent.interactionKeys,
                                          entity.interactionComponent.interactionKeys)))
        .map(trainPath => trainPath.trainPathComponent.trainColor)
        .value();
    var possibleColors = [
        '#00ccff',
        '#ff9900',
        '#9900cc',
        '#00ff99',
        '#00ffff',
        '#00ffaa',
        '#0099ff'
    ];

    var color = _.chain(possibleColors)
        .filter(possibleColor => !_.contains(existingPathColors, possibleColor))
        .first()
        .value();

    color = color ? color : '#ffffff';

    entity.trainPathComponent.trainColor = color;
};


var trainPathCircRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    if (entity.trainPathComponent.allPaths.length === 0){
        return;
    }

    var startEntity = ui.world.entityForUid(entity.trainPathComponent.trainStartId);

    if (this.renderTime < 100){
        this.renderTime += lastInterval;
    }

    var paths = [];

    _.each(entity.trainPathComponent.allPaths, function(newPath){
        paths = paths.concat(newPath);
    });

    ctx.strokeStyle = entity.trainPathComponent.trainColor
    ctx.beginPath();
    
    var startPos;
    
    if (startEntity && startEntity.focusMakingComponent){
        var cellRect = ui.world.hexMap.cellForPosComp(startEntity.positionComponent).rect;
        startPos = [cellRect[0] + cellRect[2] / 2, cellRect[1] + cellRect[3] / 2];
        ctx.moveTo(startPos[0], startPos[1]);
    }
    
    _.each(paths, (pos, i) => {
        if (i < this.renderTime * 8){
            var cellRect = ui.world.hexMap.cellForPosComp({x: pos[0], y: pos[1]}).rect;
            var pos = [cellRect[0] + cellRect[2] / 2, cellRect[1] + cellRect[3] / 2];

            if (i === 0 && !startEntity){
                ctx.moveTo(pos[0], pos[1]);
            }
            else{
                ctx.lineTo(pos[0], pos[1]);
            }
        }
    });

    ctx.stroke();
};


var getPathCurrenciesNeeded = function(entity, world){
    if (!this.memoizedCurrenciesNeeded){
        var currenciesNeeded = {};
        
        var stayAlive = _.all(this.stops, function(stopId){
            var stop = world.entityForUid(stopId);
            if (!stop){
                return false;
            }
            stop.focusPathStopComponent.updateCurrencyDictWithStop(stop, world, currenciesNeeded);
            return true;
        });

        if (!stayAlive){
            return {};
        }

        currenciesNeeded = _.chain(currenciesNeeded)
            .map(function(val, key){
                return [key, val];
            })
            .filter(function(pair){
                return pair[1] > 0;
            })
            .value();
        
        this.memoizedCurrenciesNeeded = dictFromPairs(currenciesNeeded);
    }
    return this.memoizedCurrenciesNeeded;
};

var makeTrainPath = function(entity, world){
    entity.healthComponent.kill();

    this.stops.reverse();

    if (this.stops.length > 0){
        var selfEntity = world.entityForKey(PARAMETERS.self);
        var trainPath = makeEcs(this.trainPathKey, {
            trainStartId: selfEntity.uid,
            trainStops: this.stops,
        });
        world.addEntity(trainPath);

        if (!trainPath.trainPathComponent.canMakeTrain(trainPath, world)){
            var panel = makeEcs(PARAMETERS.trainPanel, {
                key: 'trainPath_' + trainPath.uid,
                sourceId: trainPath.uid
            });
            panel.panelComponent.expandPanel();
            world.addEntity(panel);
        }

        _.each(world.entitiesForKey(PARAMETERS.trainPathMakingPanel), function(panel){
            panel.panelComponent.closed = true;
        })
    }
};

var addTrainStop = function(entity, world, stop){
    if (this.checkTrainStop(entity, world, stop)){
        if (stop.identityComponent.key == PARAMETERS.self){
            this.makeTrainPath(entity, world);
            
            if (world.gameProperties.settings.sfx){
                var sound = getAudio.get('sounds/beep.ogg');
                sound.play();
            }
        }
        else{
            this.stops.push(stop.uid);
            if (this.stops.length > 1){
                stop.rendererComponents[0].timeDrawn = 0;

                if (world.gameProperties.settings.sfx){
                    var sound = getAudio.get('sounds/beep.ogg');
                    sound.play();
                }
            }
        }
    }
    this.memoizedCurrenciesNeeded = undefined;
};

var isRelevantFocusStop = function(worldEntity, world, pathCurrenciesNeeded){
    return worldEntity.focusPathStopComponent &&
        _.any(worldEntity.focusPathStopComponent.currenciesMadeAtPoint(worldEntity, world), 
              function(key){ return pathCurrenciesNeeded[key]; });
};

var isFreeStop = function(worldEntity, world){
    return !_.any(world.entities, function(chkEntity){
        return chkEntity.trainPathComponent && _.contains(chkEntity.trainPathComponent.trainStops, worldEntity.uid);
    });
};

var checkTrainStop = function(entity, world, worldEntity){
    if (worldEntity.focusPathStopComponent && worldEntity.focusPathStopComponent.isDisabled){
        return false;
    }
    
    if (this.stops.length > 0){
        var pathCurrenciesNeeded = this.getPathCurrenciesNeeded(entity, world);

        if (Object.keys(pathCurrenciesNeeded).length > 0){
            return isRelevantFocusStop(worldEntity, world, pathCurrenciesNeeded) &&
                worldEntity.interactionComponent.canInteractSelf() &&
                !_.contains(this.stops, worldEntity.uid) &&
                isFreeStop(worldEntity, world);
        }
        else{
            return worldEntity.identityComponent && worldEntity.identityComponent.key == PARAMETERS.self;
        }
    }
    else{
        return worldEntity.focusPathStopComponent && 
            worldEntity.focusPathStopComponent.isPathEnd &&
            isFreeStop(worldEntity, world);
    }
};

var removeTrainStop = function(index){
    this.stops.splice(index, 1);
    this.memoizedCurrenciesNeeded = undefined;
};


var trainPathMakerHighlightRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    var world = ui.world;
    
    this.timeToBlink -= lastInterval;
    
    if (this.timeToBlink > 0){
        var highlightEntities = _.filter(world.entities, function(worldEntity){
            return entity.trainPathMakerComponent.checkTrainStop(entity, world, worldEntity);
        });

        _.each(highlightEntities, (worldEntity) => {
            var rect = world.hexMap.cellForPosComp(worldEntity.positionComponent).rect;
            ctx.drawImage(getImage(this.highlightImage), rect[0], rect[1]);
        });
    }
    else if (this.timeToBlink < -0.1){
        this.timeToBlink += 1;
    }
};


var trainPathMakerKill = function(entity, world){
    _.chain(world.entities)
        .filter(function(entity){
            return entity.identityComponent &&
                entity.identityComponent.key == '#trainPathMaker';
        })
        .each(function(entity){
            entity.panelComponent.closed = true;
        });
};


var trainPathMakerTick = function(entity, world){
    entity.trainPathMakerComponent.memoizedCurrenciesNeeded = undefined;
};


var trainPathMakingPanelRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    entity.panelComponent.panelButtons = [];
        
    var panelButtons = [];
    var world = ui.world;
    
    var trainPathMaker = _.chain(world.entities)
        .filter(function(worldEntity){
            return worldEntity.trainPathMakerComponent;
        })
        .first()
        .value();

    if (!trainPathMaker){
        this.completeFunction = undefined;
        this.killStopFunctions = [];
        return;
    }

    if (entity.panelComponent.closed){
        return;
    }

    var stops = trainPathMaker.trainPathMakerComponent.stops;

    if (stops.length > 0){
        entity.panelComponent.sourceId = stops[0]
    }

    entity.absolutePositionComponent.size[1] = 350 + stops.length * 60;
    rect = entity.absolutePositionComponent.getAbsPosRect();

    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);

    ctx.fillStyle = this.textColor;
    ctx.textAlign = 'center';
    ctx.font = getFont(28);
    ctx.fillText('New Train', rect[0] + rect[2] / 2, rect[1] + 40);
    ctx.textAlign = 'left';


    ctx.font = getFont(20);
    var currenciesNeeded = trainPathMaker.trainPathMakerComponent.getPathCurrenciesNeeded(trainPathMaker, world);
    currenciesNeeded = _.chain(currenciesNeeded)
        .map(function(val, key){
            return [key, val];
        })
        .filter(function(pair){
            return pair[1] > 0;
        })
        .value();
    
    var y = rect[1] + 100;
    
    if (currenciesNeeded.length > 0){
        var currencySt = 'Currencies Needed:';
        ctx.fillText(currencySt, rect[0] + 20, y);
        ctx.font = getFont(18);
        _.each(currenciesNeeded, function(pair){
            y += 30;
            var st = getSaneName(pair[0]);
            if (pair[1] > 1){
                st += ' - ' + pair[1];
            }

            for (var i = 0; i < pair[1]; i++){
                ctx.drawImage(getImage('currency'), rect[0] + 20 + 5 * i, y - 9);
            }

            ctx.fillText(st, rect[0] + 50, y + 5);
        });
        ctx.font = getFont(20);

        ctx.strokeStyle = this.insetColor;
        ctxRoundedRect([rect[0] + 10, rect[1] + 110, rect[2] - 20, y - rect[1] - 85]);
    }
    
    y += 60;
    ctx.fillText('Path Taken:', rect[0] + 20, y)
    y += 50;
    
    var startStopsY = y - 40;

    for (var i = stops.length - 1; i >= 0; i--){
        var stop = world.entityForUid(stops[i]);

        if (!stop){
            break;
        }
        
        if (this.killStopFunctions[i] === undefined){
            this.killStopFunctions[i] = function(){
                trainPathMaker.trainPathMakerComponent.removeTrainStop(i);
            };
        }

        if (stop.uiDataComponent){
            stop.uiDataComponent.drawImage(stop, world, [rect[0] + 10, y - 30]);
        }
        if (stop.identityComponent && stop.identityComponent.image){
            ctx.drawImage(getImage(stop.identityComponent.image), rect[0] + 10, y - 30);
        }

        ctx.fillStyle = this.textColor;
        if (stop.identityComponent.name.length > 20){
            ctx.font = getFont(14);
            ctx.fillText(stop.identityComponent.name, rect[0] + 80, y);
            ctx.font = getFont(20);
        }
        else{
            ctx.fillText(stop.identityComponent.name, rect[0] + 80, y);
        }
        
        if (stops.length > 1 && i == stops.length - 1){
            var removeRect = [rect[0] + rect[2] - 55, y - 20, 40, 40];
            this.drawPanelButton(removeRect, 'X');
            panelButtons.push([removeRect, this.killStopFunctions[i]]);
        }

        y += 60;
    };

    ctxRoundedRect([rect[0] + 10, startStopsY, rect[2] - 20, y - startStopsY - 10]);

    if (stops.length > 0 && Object.keys(currenciesNeeded).length == 0){
        if (this.completeFunction === undefined){
            this.completeFunction = function(){
                trainPathMaker.trainPathMakerComponent.makeTrainPath(trainPathMaker, world);
                if (world.gameProperties.settings.sfx){
                    var sound = getAudio.get('sounds/beep.ogg');
                    sound.play();
                }
            };
        }

        this.blinkTime -= lastInterval;
        if (this.blinkTime < -0.2){
            this.blinkTime += 1;
        }
        
        var completeX = rect[0] + rect[2] / 2 - 75;
        var completeY = y + 20;

        var completeRect = [completeX, completeY, 150, 30];

        ctx.strokeStyle = (this.blinkTime > 0) ? '#000000' : '#ff0000';
        ctxRoundedRect(completeRect);

        ctx.fillStyle = this.textColor;
        ctx.drawImage(getImage(this.trainIcon), completeX + 5, completeY);
        ctx.fillText('Start Train', completeX + 45, completeY + 20);

        panelButtons.push([completeRect, this.completeFunction]);
    }

    entity.panelComponent.panelButtons = panelButtons;

    ctx.font = getFont(20);
    
    var closeRect = [rect[0] + rect[2] / 2 - 50, rect[1] + rect[3] - 50, 100, 40];
    this.drawPanelButton(closeRect, 'CLOSE');
    
    entity.panelComponent.panelButtons.push([closeRect, entityPanelClose]);    

    ctx.font = BASE_FONT;
};


var builtSourceMapSpawnPos = function(entity, world){
    var sourceEntities = _.filter(world.entities, function(chkEntity){
        return chkEntity.sourceExtensionComponent && 
            chkEntity.sourceExtensionComponent.sourceKey == entity.identityComponent.key;
    });
    
    sourceEntities.push(entity);

    var blockingEntities = world.getBlockingEntities();
    blockingEntities.push(entity);

    var blockingPositions = _.map(blockingEntities, 
                                  blockingEntity => [blockingEntity.positionComponent.x, blockingEntity.positionComponent.y]);
    var shallowBlockers = _.clone(blockingPositions);

    var checkForDifferentTrait = function(blockingEntity){
        if (!(blockingEntity.sourceExtensionComponent || blockingEntity.entityManagerComponent)){
            return false;
        }

        if (entity.personHeldComponent){
            if (!blockingEntity.personHeldComponent){
                return true;
            }
            return blockingEntity.personHeldComponent.personHeld != entity.personHeldComponent.personHeld;
        }

        return (blockingEntity.sourceExtensionComponent && 
                blockingEntity.sourceExtensionComponent.sourceKey != entity.identityComponent.key) ||
            (blockingEntity.entityManagerComponent && 
             blockingEntity.identityComponent.key != entity.identityComponent.key)
    };


    _.chain(blockingEntities)
        .filter(blockingEntity => checkForDifferentTrait(blockingEntity))
        .each(function(blockingEntity){
            _.each(world.hexMap.neighbors(blockingEntity.positionComponent.x, blockingEntity.positionComponent.y), 
                   function(pos){ blockingPositions.push(pos); });
        });

    var getAdjPos = (checkPositions) => {
        var positions = _.chain(sourceEntities)
            .map(posEntity => world.hexMap.neighbors(posEntity.positionComponent.x, posEntity.positionComponent.y))
            .flatten(true)
            .filter(function(neighbor){
                return world.isPosInBounds(neighbor) &&
                    !_.any(checkPositions, blockingPos => comparePos(blockingPos, neighbor));
            })
            .value();
        
        if (this.tendPosition){
            return _.min(positions, position => (Math.abs(position[0] - this.tendPosition[0]) + 
                                                 Math.abs(position[1] - this.tendPosition[1])));
        }
        else{
            return _.sample(positions);
        }
    };
    var adjPos = getAdjPos(blockingPositions);

    if (!adjPos){
        adjPos = getAdjPos(shallowBlockers);
    }

    if (!adjPos){
        this.spawnDone = true;
    }

    return adjPos;
};

var builtSourceMapShouldSpawn = function(entity, world, spawnedEntities){
    var level = entity.experienceComponent.getXpLevel(entity);
    var count = _.filter(world.entities, function(worldEntity){
        return worldEntity.sourceExtensionComponent &&
            worldEntity.sourceExtensionComponent.sourceKey == entity.identityComponent.key;
    }).length + 1 + spawnedEntities.length;
    return (count < level) && !this.spawnDone;
};


var killExtensions = function(entity, world){
    _.each(world.entitiesForKey(entity.mapSpawnComponent.mapSpawnKey), function(extension){
        extension.healthComponent.health = 0;
    });
};


var builtSourceCreateExec = function(entity, world){
    if (this.randomTraitPosition){
        randomOpenTraitPositionExec(entity, world, this.sector);
    }
    if (this.skipBuiltSourceCreate){
        return;
    }
    
    entity.experienceComponent.updateExpansion(entity);

    var spawnedEntities = [];

    while (entity.mapSpawnComponent.mapShouldSpawn(entity, world, [])){
        var spawnedEntity = entity.mapSpawnComponent.mapSpawn(entity, world, spawnedEntities);
        if (spawnedEntity){
            spawnedEntities.push(spawnedEntity);
            world.entityDeath();
        }
        else{
            break;
        }
    }

    spawnedEntities = [entity].concat(spawnedEntities);

    //spawnedEntities = _.shuffle(spawnedEntities);

    _.each(this.startManagedEntities, function(entityKey, i){
        world.makeEntities(entity, entityKey, {
            x: spawnedEntities[i].positionComponent.x,
            y: spawnedEntities[i].positionComponent.y,
            sourceTrait: entity.identityComponent.key
        });
    });
};

var randomOpenTraitPositionExec = function(entity, world, sector){
    var pos;
    if (entity.personHeldComponent){
        var blockingEntities = world.getBlockingEntities();
        var personEntityKeys = _.chain(world.entities)
            .filter(function(worldEntity){
                return worldEntity.personHeldComponent &&
                    worldEntity.personHeldComponent.personHeld == entity.personHeldComponent.personHeld &&
                    worldEntity.identityComponent &&
                    worldEntity.positionComponent;
            })
            .map(function(worldEntity){ return worldEntity.identityComponent.key; })
            .value();
        
        var positions = _.chain(world.entities)
            .filter(function(worldEntity){
                return (worldEntity.identityComponent &&
                        _.contains(personEntityKeys, worldEntity.identityComponent.key)) ||
                    (worldEntity.sourceExtensionComponent &&
                     _.contains(personEntityKeys, worldEntity.sourceExtensionComponent.sourceKey));
            }) 
            .map(function(worldEntity){
                return world.hexMap.neighbors(worldEntity.positionComponent.x, worldEntity.positionComponent.y);
            })
            .flatten(true)
            .filter(function(neighbor){
                return world.isPosInBounds(neighbor) &&
                    !_.any(blockingEntities, function(blockingEntity){
                        return blockingEntity.positionComponent.isPos(neighbor);
                    });
            })
            .value();
        
        if (positions.length > 0){
            if (sector){
                var sectorPosition = getSectorPos(sector);
                pos = _.min(positions, function(position){
                    var xdiff = Math.abs(position[0] - sectorPosition[0]);
                    var ydiff = Math.abs(position[1] - sectorPosition[1]);
                    return xdiff + ydiff;
                });
            }
            else{
                pos = _.sample(positions);
            }
            
            if (pos){
                entity.positionComponent.setPos(pos);
                return;
            }
        }
    }
    
    if (sector === undefined){
        pos = world.randomOpenPosition(entity.positionComponent.planeOfExistence);
        var entitiesToCheck = _.filter(world.entities, function(worldEntity){
            return ((worldEntity.identityComponent && worldEntity.identityComponent.key == PARAMETERS.self) ||
                    worldEntity.entityManagerComponent ||
                    worldEntity.sourceExtensionComponent);
        });
        
        var neighborPos = _.chain(world.hexMap.neighbors(pos[0], pos[1]))
            .filter(function(neighbor){
                if (!world.isPosInBounds(neighbor)){
                    return false;
                }
                var step = world.hexMap.neighbors(neighbor[0], neighbor[1]);
                return _.all(step, function(position){
                    return !_.any(entitiesToCheck, function(chkEntity){ return chkEntity.positionComponent.isPos(position); });
                });
            })
            .sample()
            .value();

        entity.positionComponent.setPos(neighborPos ? neighborPos : pos);
    }
    else{
        pos = false;
        var entitiesToCheck = world.getPositionedEntities(entity.positionComponent.planeOfExistence);
        var attempts = 0;
        while (!pos){
            pos = getSectorPos(sector);
            
            if (_.any(entitiesToCheck, function(chkEntity){
                return chkEntity.positionComponent.isPos(pos);
            })){
                pos = false;
                attempts += 1;
                if (attempts > 10){
                    break;
                }
            }
        }

        if (pos){
            entity.positionComponent.setPos(pos);
        }
        else{
            randomOpenTraitPositionExec(entity, world, undefined);
        }
    }
};

var getSectorPos = function(sector){
    return _.map(sector, function(sectorIndex, i){
        var sectorSize = PARAMETERS.size[i] / PARAMETERS.sectors[i];
        var specificIndex = sectorIndex + Math.random();
        var p = Math.floor(specificIndex * sectorSize);
        return min(max(p, 1), PARAMETERS.size[i] - 2);
    });
};


var builtSourceRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    var image = getImage(entity.entityManagerComponent.disabled ? this.disabledImage : this.image);
    var xDiff = this.getWobble(lastInterval);
    var x = rect[0] + xDiff;
    ctx.drawImage(image, x, rect[1]);

    var world = ui.world;
    var button = world.currentMakingEntity;
    if (button){
        if (button.buttonControlComponent.checkMakePos(world, entity.positionComponent.getAsPos())){
            ctx.drawImage(getImage(this.outlineImage), x, rect[1]);
        }
    }

    if (entity.entityManagerComponent.hasNew){
        this.timeToBlink -= lastInterval;
        if (this.timeToBlink > 0){
            ctx.drawImage(getImage(this.newImage), x, rect[1]);
        }
        else if (this.timeToBlink < -0.1){
            this.timeToBlink += 1;
        }
    }
};


var traitMenuCloseExec = function(entity, world){
    entity.entityManagerComponent.hasNew = false;
    _.chain(world.entities)
        .filter(worldEntity => (worldEntity.buttonControlComponent && 
                                worldEntity.buttonControlComponent.managerKey == entity.identityComponent.key))
        .each(worldEntity => worldEntity.buttonControlComponent.isNew = false);
};


var traitPanelRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    entity.panelComponent.panelButtons = [];
    if (entity.panelComponent.closed || entity.panelComponent.minimized){
        this.renderTime = 0;
        return;
    }

    this.snapPanelPos(entity);

    var world = ui.world;
    var trait = world.entityForUid(entity.panelComponent.sourceId);

    if (!trait){
        entity.panelComponent.closed = true;
        return;
    }

    var towerButtons = _.filter(world.entities, function(worldEntity){
        return worldEntity.buttonControlComponent &&
            worldEntity.buttonControlComponent.managerKey == trait.identityComponent.key;
    });

    var categories = _.chain(towerButtons)
            .map(function(button){ return button.uiDataComponent.subPanel; })
            .uniq()
            .sortBy(_.identity)
            .reverse()
            .value();

    if (!this.currentCategory){
        this.currentCategory = categories[0];
    }

    var getButtons = () => _.filter(towerButtons, towerButton => towerButton.uiDataComponent.subPanel == this.currentCategory);
    
    var buttons = getButtons();

    if (buttons.length == 0 && towerButtons.length > 0){
        this.currentCategory = towerButtons[0].uiDataComponent.subPanel;
        buttons = getButtons();
    }

    entity.absolutePositionComponent.size[1] = 275 + (buttons.length + 1) * 70;
    rect = entity.absolutePositionComponent.getAbsPosRect();

    if (this.renderTime < this.animatingTime){
        this.renderTime += lastInterval;
        var fraction = this.renderTime / this.animatingTime;
        ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2] * fraction, rect[3] * fraction);
        return;
    }
    
    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);

    entity.panelComponent.panelButtons.push(this.drawHelpButton(entity, rect));

    ctx.fillStyle = this.textColor;
    ctx.font = getFont(40);
    
    var titleWidth = ctx.measureText(trait.identityComponent.name).width;

    ctx.fillText(trait.identityComponent.name, rect[0] + (rect[2] - titleWidth) / 2, rect[1] + 60);

    ctx.font = getFont(20);

    if (trait.identityComponent.sourceName && trait.memoryComponent){
        ctx.fillText('Created by: ' + trait.identityComponent.sourceName, rect[0] + 10, rect[1] + 100);
    }

    if (trait.descriptionComponent.description){
        var y = rect[1] + 140;
        ctx.font = (trait.descriptionComponent.description.length > 75) ? '14px OpenSansItalic' : '20px OpenSansItalic';

        ctx.fillText(trait.descriptionComponent.description, rect[0] + 10, y);
        
        ctx.font = getFont(20);
    }
    
    y = rect[1] + 200;

    var standardRender = true;
    if (trait.entityManagerComponent.disabled){
        var disablingEntity = _.chain(world.entities)
            .filter(worldEntity => worldEntity.disableTraitComponent && worldEntity.disableTraitComponent.checkTraitDisabled(trait))
            .first()
            .value();
        ctx.fillText('Disabled: ' + disablingEntity.identityComponent.name, rect[0] + 10, y);
        standardRender = false;
    }
    else if (!trait.interactionComponent.canInteractSelf()){
        ctx.fillText('You have no control over this trait.', rect[0] + 10, y);
        standardRender = false;
    }
    else if (!_.contains(trait.interactionComponent.connectionKeys, PARAMETERS.self)){
        var start = world.entityForKey(PARAMETERS.self).positionComponent.getAsPos();
        var end = trait.positionComponent.getAsPos();
        if (!determinePath(start, end, world.getAllPaths())){
            ctx.fillText('You need to connect to this trait before you can build on it.', rect[0] + 10, y);
            standardRender = false;
        }
        else{
            trait.interactionComponent.connectionKeys.push(PARAMETERS.self);
        }
    }

    if (standardRender){
        _.each(categories, (panelKey, i) => {
            var catWidth  = 140;
            var x = rect[0] + 10 + (catWidth + 10) * i;
            if (panelKey == this.currentCategory){
                ctx.strokeStyle = this.insetColor;
                
                var textWidth = ctx.measureText(panelKey).width;
                ctx.fillText(panelKey, x + catWidth / 2 - textWidth / 2, y - 10);
                ctx.fillRect(x, y - 5, catWidth, 2);
            }
            else{
                var panelRect = [x, y - 30, catWidth, 30];

                var color = _.any(towerButtons, button => button.uiDataComponent.subPanel == panelKey && button.buttonControlComponent.isNew) ? '#ffd700' : '#000000';

                this.insetColor = color;
                
                this.drawPanelButton(panelRect, panelKey);

                this.insetColor = '#000000';
                
                if (!this.setCategoryFn[panelKey]){
                    this.setCategoryFn[panelKey] = () => {
                        this.currentCategory = panelKey;
                    };
                }
                var setCategoryFn = this.setCategoryFn[panelKey];
                entity.panelComponent.panelButtons.push([panelRect, setCategoryFn]);
            }
        });

        
        
        if (buttons.length > 0){
            y += 70;
            _.each(buttons, (button, i) => {
                ctx.fillStyle = this.textColor;
                
                ctx.drawImage(getImage(trait.uiDataComponent.image), rect[0] + 15, y - 26);
                button.uiDataComponent.drawImage(button, world, [rect[0] + 15, y - 26]);
                                
                ctx.fillText(button.identityComponent.name, rect[0] + 80, y + 10);

                ctx.font = '14px OpenSansItalic';
                if (_.isArray(button.descriptionComponent.description)){
                    _.each(button.descriptionComponent.description, (desc, i) => {
                        ctx.fillText(desc, rect[0] + 320, y + 15 * i);
                    });
                }
                else{
                    if (button.descriptionComponent.description.length > 50){
                        ctx.font = '12px OpenSansItalic';
                    }
                    ctx.fillText(button.descriptionComponent.description, rect[0] + 325, y + 10);
                }
                
                if (!button.interactionComponent.canInteractSelf()){
                    ctx.font = getFont(14);
                    ctx.fillText('No Control', rect[0] + rect[2] - 100, y + 7);
                    ctx.font = getFont(20);
                }
                else if (button.buttonControlComponent.canMakeEntity(world)){
                    ctx.font = getFont(20);
                    var buttonRect = [rect[0] + rect[2] - 100, y - 15, 70, 30];

                    this.drawPanelButton(buttonRect, 'Build')
                    
                    var buildFunction = button.buttonControlComponent.getWrappedFunction(button, world, ui);
                    entity.panelComponent.panelButtons.push([buttonRect, buildFunction]);
                }
                else{
                    ctx.font = getFont(14);
                    ctx.fillText('Limit', rect[0] + rect[2] - 100, y);
                    ctx.fillText('Reached', rect[0] + rect[2] - 100, y + 15);
                    ctx.font = getFont(20);
                }

                if (button.buttonControlComponent.displayRiskIcon){
                    ctx.drawImage(getImage('dice'), rect[0] + 11, y - 29, 18, 18);
                }

                ctx.strokeStyle = button.buttonControlComponent.isNew ? '#ffd700' : '#000000';
                ctxRoundedRect([rect[0] + 10, y - 30, rect[2] - 20, 60]);
                ctx.strokeStyle = '#000000';
                y += 70;
            });
        }
    }
    
    var closeRect = [rect[0] + rect[2] / 2 - 50, rect[1] + rect[3] - 50, 100, 40];
    this.drawPanelButton(closeRect, 'CLOSE');
    entity.panelComponent.panelButtons.push([closeRect, entityPanelClose]);    

    ctx.font = BASE_FONT;
};


var checkTraitParticleEffectAlive = function(entity, world){
    var manager = world.entityForKey(this.managerKey);
    return manager && manager.entityManagerComponent.hasNew;
};


var transformTrait = function(entity, world){
    world.transformTrait(this.sourceTrait, this.newTrait, this.retainHealth);
};


var tutorialTextRender = function(rect, entity, ui){
    var world = ui.world;
    var entityToMark = world.entityForKey(this.entityToMark);
    
    if (entityToMark.positionComponent){
        rect = _.clone(world.hexMap.cellForPosComp(entityToMark.positionComponent).rect);
    }
    else if (entityToMark.absolutePositionComponent){
        rect = entityToMark.absolutePositionComponent.getAbsPosRect();
    }
    else{
        rect = [0, 0, 0, 0];
    }
    
    ctx.fillStyle = '#ffffff';
    ctx.font = getFont(30);

    var y = max(rect[1] + this.yOffset - 20, 32);

    ctx.fillText(this.text, rect[0] + this.xOffset, y);
    var textWidth = ctx.measureText(this.text).width;
    ctx.font = BASE_FONT;
    
    this.drawArrow([rect[0] + this.xOffset + textWidth / 2, y + 10],
                   [rect[0] + rect[2], rect[1] + rect[3] / 2]);
};

var tutorialTextDrawArrow = function(startPos, endPos){
    ctx.strokeStyle = '#ffffff';
    ctx.beginPath();
    ctx.moveTo(startPos[0], startPos[1]);
    ctx.bezierCurveTo(startPos[0] + 20, startPos[1] + 20,
                      endPos[0] + 10, endPos[1],
                      endPos[0], endPos[1]);
    ctx.lineTo(endPos[0] + 10, endPos[1] - 6);
    ctx.moveTo(endPos[0], endPos[1]);
    ctx.lineTo(endPos[0] + 10, endPos[1] + 6);
    ctx.stroke();
};


var tutorialTextTutorialDone = function(entity, world){
    var markingEntity = world.entityForKey(entity.tutorialTextComponent.entityToMark);
    if (!markingEntity){
        return true;
    }

    return this.checkTutorialUiKey(markingEntity, world);
    
};

var checkTutorialUiKey = function(markingEntity, world){
    var uiKey = markingEntity.clickComponent.uiKey;
    var panel = world.entityForKey(uiKey);
    if (panel === undefined){
        return false;
    }
    return !panel.panelComponent.closed;
};


var tutorialUnpauseRender = function(rect, entity, ui){
    ctx.fillStyle = '#ffffff';
    ctx.font = getFont(30);
    _.each(this.text, (txt, i) => ctx.fillText(txt, 50, this.yStart + 50 * i));
    ctx.font = BASE_FONT;

    ctx.strokeStyle = '#ffffff';
    ctx.beginPath();
    ctx.moveTo(50, this.yStart + 50 * (this.text.length - 1) + 25);
    ctx.bezierCurveTo(25, 625,
                      25, 700,
                      50, 760);
    ctx.lineTo(44, 754);
    ctx.moveTo(50, 760);
    ctx.lineTo(56, 754);
    ctx.stroke();
};


var tutorialUnpauseTutorialDone = function(entity, world){
    return world.game.tickSystemWrapper.running;
};


var getUiActions = function(entity, ui, panel){
    if (!(this.memoizedActions && (Object.keys(this.memoizedActions).length > 0) && _.all(this.memoizedActions, _.identity))){
        this.memoizedActions = this.generateUiActions(entity, ui, panel);
    }
    
    return this.memoizedActions;
};


var uiDataDrawImage = function(entity, world, pos){
    var managerKey = false;
    if (entity.managedComponent){
        managerKey = entity.managedComponent.managerKey;
    }
    if (entity.buttonControlComponent){
        managerKey = entity.buttonControlComponent.managerKey;
    }
    
    if (managerKey){
        var imageKey;
        if (allArgs[managerKey]){
            imageKey = allArgs[managerKey].image;
        }
        else{
            var manager = world.entityForKey(managerKey);
            if (manager){
                imageKey = manager.uiDataComponent.image;
            }
        }

        if (imageKey){
            ctx.drawImage(getImage(imageKey), pos[0], pos[1]);
        }
    }
    ctx.drawImage(getImage(this.image), pos[0], pos[1]);
};


var upgradeTower = function(world, pos, entity, interactionKey){
    var toUpgrade = this.baseUpgradeTowerForPos(world, pos);
        
    toUpgrade.healthComponent.kill();

    var args = {
        x: pos[0],
        y: pos[1],
        sourceKey: toUpgrade.managedComponent.managerKey,
        sourceTrait: toUpgrade.managedComponent.managerKey
    };

    if (interactionKey){
        args.interactionKeys = [interactionKey];
    }
    
    var newEntity = makeEcs(this.constructionKey, args);
    
    return newEntity;
};

var canMakeUpgrade = function(world){
    return _.any(this.baseKeys, function(baseKey){
        return world.entityForKeyExists(baseKey);
    });
};

var checkUpgradePos = function(world, pos){
    return this.baseUpgradeTowerForPos(world, pos) !== undefined;
};

var baseUpgradeTowerForPos = function(world, pos){
    return _.chain(this.baseKeys)
        .map(function(baseKey){
            return world.entitiesForKey(baseKey);
        })
        .flatten(true)
        .filter(function(baseEntity){
            return baseEntity.positionComponent.isPos(pos);
        })
        .first()
        .value();
};



var utilityEntityRender = function(rect, entity, ui){
    ctx.drawImage(getImage(this.backImage), rect[0], rect[1], rect[2], rect[3]);
    entity.panelComponent.panelButtons = [];

    if (!this.showAllBuildingPanel){
        this.showAllBuildingPanel = function(){
            var menu = ui.world.entityForKey(PARAMETERS.allBuildingPanel);
            if (!menu){
                menu = makeEcs(PARAMETERS.allBuildingPanel);
                ui.world.addEntity(menu);
            }
            
            menu.panelComponent.expandPanel();
        };
    }

    ctx.fillStyle = this.textColor;
    
    var buildingRect = [rect[0] + rect[2] / 2 - 75, rect[1] + rect[3] / 2 - 15, 150, 30];
    this.drawPanelButton(buildingRect, 'All Buildings');
    entity.panelComponent.panelButtons.push([buildingRect, this.showAllBuildingPanel]);
};


var getWobble = function(lastInterval){
    var xDiff = 0;
    if (this.wobble > 0){
        xDiff = 3 * Math.sin(this.wobble);
        this.wobble -= lastInterval * 8 * Math.PI;
    }
    return xDiff;
}


var calculateWorkerTicks = function(entity, world){
    var xpFactor = 1;
    if (entity.managedComponent){
        var manager = world.entityForKey(entity.managedComponent.managerKey);
        xpFactor = (1 - Math.pow(1/2, manager.experienceComponent.currentLevel)) * 2;
    }
    var workerFactor = (1 - Math.pow(1/2, this.workersActive.length)) * 2;
    return xpFactor * workerFactor;
};


var checkWorldGoalComponent = function(entity){
    return _.all(entity.worldGoalComponent.currencyRequested, function(val){ return val <= 0; });
};


var makeGoalMenuExecute = function(entity, world){
    if (entity.interactionComponent.canInteractSelf()){
        world.makeEntities(entity, this.goalMenuKey);
    }
};


var trackActionables = function(entity, world){
    world.trackActionables();
};


var worldGoalRender = function(rect, entity, ui, rectCount, timeToNextTick, lastInterval){
    var x = rect[0] + this.getWobble(lastInterval);
    ctx.drawImage(getImage(this.image), x, rect[1]);
    ctx.fillStyle = entity.worldGoalComponent.requestingCurrency ? '#ffffff' : '#000000';
    
    if (this.outlineImage){
        ctx.drawImage(getImage(this.outlineImage), x, rect[1]);
        this.outlineImage = false;

        this.renderTrainIcon(lastInterval, x, rect[1]);
    }

    if (!entity.worldGoalComponent.goalSeen && entity.interactionComponent.canInteractSelf()){
        this.timeToBlink -= lastInterval;
        if (this.timeToBlink > 0){
            ctx.drawImage(getImage(this.newImage), x, rect[1]);
        }
        else if (this.timeToBlink < -0.1){
            this.timeToBlink += 1;
        }
    }
};


var worldGoalGetCurrencyComponent = function(entity){
    return entity.worldGoalComponent;
};


var worldGoalMenuOpened = function(entity, args){
    if (args.menuSourceKey == entity.uid){
        entity.worldGoalComponent.goalSeen = true;
        entity.pauseComponent.paused = false;
    }
};


var chkForPlayerInterruptExec = function(entity, world){
    if (entity.interactionComponent.canInteract(PARAMETERS.self)){
        this.playerExecute.execute(entity, world);
    }
    else{
        entity.pauseComponent.paused = false;
    }
};


var checkWorldGoalParticleEffectAlive = function(entity, world){
    var source = world.entityForUid(this.sourceId);
    if (!source){
        return false;
    }
    return !source.worldGoalComponent.goalSeen;
};


var choreReplaceMarker = function(entity, world){
    if (world.entityForKey(this.traitKey)){
        return _.sample(this.goalKeys);
    }
    return this.traitKey;
};


var explodeTraitExec = function(entity, world){
    _.chain(world.entities)
        .filter(worldEntity => (worldEntity.identityComponent && worldEntity.identityComponent.key == this.traitToExplode) ||
                (worldEntity.sourceExtensionComponent && worldEntity.sourceExtensionComponent.sourceKey == this.traitToExplode))
        .chain((worldEntity) => {
            var emotionKey = _.sample(this.emotionKeys);
            world.makeEcs(worldEntity, emotionKey);
        })

    entity.healthComponent.kill();
};


var defineRoleGetReplaceKeys = function(entity, world){
    var canBuild = _.filter(this.possiblePairs, pair => !world.entityForKey(pair[0]));
    var keys = _.sample(canBuild);
    
    if (canBuild.length < 2){
        keys = keys.concat(this.exhaustEntities);
    }
    
    return keys;
};


var expandTraitExec = function(entity, world){
    var traitToExpand = world.entityForKey(this.traitToExpand);
    if (traitToExpand){
        traitToExpand.experienceComponent.maxLevel = min(this.maxExpansion, traitToExpand.experienceComponent.mexLevel + 1);

        while (traitToExpand.mapSpawnComponent.mapShouldSpawn(traitToExpand, world, [])){
            var spawnedEntity = traitToExpand.mapSpawnComponent.mapSpawn(traitToExpand, world, spawnedEntities);
            if (spawnedEntity){
                spawnedEntities.push(spawnedEntity);
                world.entityDeath();
            }
            else{
                break;
            }
        }
    }
    entity.healthComponent.kill();
};


var splitReplaceGetKeys = function(entity, world){
    return this.source ? (this.source.interactionComponent.canInteractSelf() ? this.youKeys : this.himKeys) : null
};


var switchGetReplaceKeys = function(entity, world, baseArgs){
    baseArgs.interactionKeys = (_.contains(baseArgs.interactionKeys, 'self')) ? ['himself'] : ['self'];
    return this.entitiesToMake;
};
                               



var csvIdentifiers = {
    "instantEmotionOther": [], 
    "sourceExtension": [
        "you_ext", 
        "worthless_ext", 
        "insecurity_ext", 
        "critical_ext", 
        "searchingWorth_ext", 
        "helpful_ext", 
        "restLife_ext", 
        "him_ext", 
        "restless_ext", 
        "hisWork_ext", 
        "faithCrisis_ext", 
        "hisGoodWork_ext", 
        "hisBadWork_ext", 
        "capable_ext", 
        "newRelationship_ext", 
        "relationship_ext", 
        "conversation_ext", 
        "good_ext", 
        "selfish_ext", 
        "warm_ext", 
        "clever_ext", 
        "hurting_ext", 
        "strong_ext", 
        "tempTrait_ext"
    ], 
    "qualityResource": [], 
    "paramPath": [], 
    "resourceModifier": [], 
    "personGoal": [], 
    "changeOpinion": [], 
    "worldGoal": [
        "insecureGoal", 
        "obsessGoal", 
        "becomeCriticalGoal", 
        "quietCriticismGoal", 
        "criticizeSelfGoal", 
        "startRelationYouGoal", 
        "startRelationHimGoal", 
        "tryForConnectionYouGoal", 
        "acceptConnectionYouGoal", 
        "tryForConnectionHimGoal", 
        "acceptConnectionHimGoal", 
        "flirtYouGoal", 
        "flirtHimGoal", 
        "forceOpennessGoal", 
        "quietTimeGoal", 
        "pushInsecurityGoal", 
        "getOverGoodWorkGoal", 
        "getOverBadWorkGoal", 
        "searchWorthGoal", 
        "probeTopicGoal", 
        "defineRoleGoal", 
        "planSomethingFunGoal", 
        "doFunGoal", 
        "findUsefulGoal", 
        "doUsefulGoal", 
        "thankGoal", 
        "accuseSelfishGoal", 
        "askHelpGoal", 
        "helpGoal", 
        "needWorkGoal", 
        "choreGoal", 
        "acceptMeanlessGoal", 
        "rejectMeanlessGoal", 
        "tryNewGoal", 
        "exploreNewGoal", 
        "defineHelpGoal", 
        "findHelpGoal", 
        "beHelpGoal", 
        "feelUselessGoal", 
        "winGoal", 
        "startConverseGoal", 
        "appreciateWorkGoal", 
        "deriveWorkTopicGoal", 
        "askAboutRestlessGoal", 
        "talkAboutHimGoal", 
        "talkAboutYouGoal", 
        "needHelpGoal", 
        "guiltGoal", 
        "fascinateGoal", 
        "learnHimGoal", 
        "noticeThingGoal", 
        "findLifeHelpGoal", 
        "hisGraciousGoal", 
        "getFeedbackGoal", 
        "himSupportGoal", 
        "noSupportGoal", 
        "whatsNewGoal", 
        "niceGoal", 
        "sharePainGoal", 
        "overcomeHurtGoal", 
        "calmPartnerGoal", 
        "talkInterestingGoal", 
        "overcomeCrisisGoal", 
        "supportCrisisGoal", 
        "triggerCrisisGoal", 
        "feedCrisisGoal", 
        "soberDownGoal", 
        "loosenUpGoal", 
        "hardWorkGoal", 
        "completeWorkGoal", 
        "connectHurtGoal", 
        "beSupportedGoal", 
        "diveHurtGoal", 
        "exploreStrengthGoal", 
        "learnHistoryGoal", 
        "giveInGoal", 
        "allowWeaknessGoal", 
        "reachOutGoal", 
        "takeConnectGoal", 
        "openUpGoal", 
        "spendTimeGoal", 
        "makeComplimentSwarmGoal", 
        "makeComplimentFlatGoal", 
        "makeCriticismSwarmGoal", 
        "makeCriticismFlatGoal", 
        "makeOldFailSwarmGoal", 
        "makeOldFailFlatGoal", 
        "makeSlowWorkSwarmGoal", 
        "makeSlowWorkFlatGoal", 
        "makeStupidityFlatGoal", 
        "makeDreamDeathMajorGoal", 
        "makeWorkWinMajorGoal", 
        "minorInterruptGoal", 
        "reinforceComplimentGoal", 
        "reinforceCriticismGoal", 
        "reinforceOldFailGoal", 
        "reinforceViceGoal", 
        "reinforceStupidGoal", 
        "trySomethingGoal", 
        "complimentYouGoal", 
        "speakOfValueGoal", 
        "takeOutFrustrationGoal", 
        "beBelievedInGoal", 
        "askForBeliefGoal", 
        "takeStrengthGoal", 
        "spendTimeWarmGoal", 
        "spendTimeCleverGoal", 
        "indulgeViceGoal", 
        "fishComplimentsGoal", 
        "openResponseGoal", 
        "cleverResponseGoal", 
        "connectFriendsGoal", 
        "convinceActivityGoal"
    ], 
    "goalCompleteMenu": [
        "gameStartMenu", 
        "startRelationYouMenu", 
        "findUsefulMenu", 
        "flirtYouMenu", 
        "forceOpennessMenu", 
        "pushInsecurityMenu", 
        "guiltMenu", 
        "defineRoleMenu", 
        "findHelpMenu", 
        "learnHimMenu", 
        "feedCrisisMenu", 
        "winMenu", 
        "allowWeaknessMenu", 
        "needHelpMenu", 
        "overcomeHurtMenu", 
        "breakdownMenu", 
        "insecureMenu", 
        "obsessMenu", 
        "becomeCriticalMenu", 
        "quietCriticismMenu", 
        "criticizeSelfMenu", 
        "startRelationHimMenu", 
        "tryForConnectionYouMenu", 
        "acceptConnectionYouMenu", 
        "tryForConnectionHimMenu", 
        "acceptConnectionHimMenu", 
        "flirtHimMenu", 
        "quietTimeMenu", 
        "getOverGoodWorkMenu", 
        "getOverBadWorkMenu", 
        "searchWorthMenu", 
        "probeTopicMenu", 
        "planSomethingFunMenu", 
        "doFunMenu", 
        "doUsefulMenu", 
        "thankMenu", 
        "accuseSelfishMenu", 
        "askHelpMenu", 
        "helpMenu", 
        "needWorkMenu", 
        "choreMenu", 
        "acceptMeanlessMenu", 
        "rejectMeanlessMenu", 
        "tryNewMenu", 
        "exploreNewMenu", 
        "defineHelpMenu", 
        "beHelpMenu", 
        "feelUselessMenu", 
        "startConverseMenu", 
        "appreciateWorkMenu", 
        "deriveWorkTopicMenu", 
        "askAboutRestlessMenu", 
        "talkAboutHimMenu", 
        "talkAboutYouMenu", 
        "fascinateMenu", 
        "noticeThingMenu", 
        "findLifeHelpMenu", 
        "hisGraciousMenu", 
        "getFeedbackMenu", 
        "himSupportMenu", 
        "noSupportMenu", 
        "whatsNewMenu", 
        "niceMenu", 
        "sharePainMenu", 
        "calmPartnerMenu", 
        "talkInterestingMenu", 
        "overcomeCrisisMenu", 
        "supportCrisisMenu", 
        "triggerCrisisMenu", 
        "soberDownMenu", 
        "loosenUpMenu", 
        "hardWorkMenu", 
        "completeWorkMenu", 
        "connectHurtMenu", 
        "beSupportedMenu", 
        "diveHurtMenu", 
        "exploreStrengthMenu", 
        "learnHistoryMenu", 
        "giveInMenu", 
        "reachOutMenu", 
        "takeConnectMenu", 
        "openUpMenu", 
        "spendTimeMenu", 
        "makeComplimentSwarmMenu", 
        "makeComplimentFlatMenu", 
        "makeCriticismSwarmMenu", 
        "makeCriticismFlatMenu", 
        "makeOldFailSwarmMenu", 
        "makeOldFailFlatMenu", 
        "makeSlowWorkSwarmMenu", 
        "makeSlowWorkFlatMenu", 
        "makeStupidityFlatMenu", 
        "makeDreamDeathMajorMenu", 
        "makeWorkWinMajorMenu", 
        "minorInterruptMenu", 
        "reinforceComplimentMenu", 
        "reinforceCriticismMenu", 
        "reinforceOldFailMenu", 
        "reinforceViceMenu", 
        "reinforceStupidMenu", 
        "trySomethingMenu", 
        "complimentYouMenu", 
        "speakOfValueMenu", 
        "takeOutFrustrationMenu", 
        "beBelievedInMenu", 
        "askForBeliefMenu", 
        "takeStrengthMenu", 
        "spendTimeWarmMenu", 
        "spendTimeCleverMenu", 
        "indulgeViceMenu", 
        "fishComplimentsMenu", 
        "openResponseMenu", 
        "cleverResponseMenu", 
        "connectFriendsMenu", 
        "convinceActivityMenu"
    ], 
    "memoryFade": [], 
    "splitReplace": [
        "guiltEmo", 
        "interestingEmo", 
        "casualEmo", 
        "oldEmo"
    ], 
    "currency": [
        "anxiety", 
        "obsession", 
        "openness", 
        "flirtation", 
        "calm", 
        "topic", 
        "probedProblem", 
        "push", 
        "activity", 
        "thought", 
        "helpHim", 
        "value", 
        "workTopic", 
        "need", 
        "interesting", 
        "support", 
        "hisEmotion", 
        "busyWork", 
        "caring", 
        "cheer", 
        "completeWork", 
        "compliment", 
        "criticism", 
        "cruelty", 
        "frustration", 
        "goodness", 
        "goodWork", 
        "impulse", 
        "insecure", 
        "meditation", 
        "pain", 
        "relationshipTime", 
        "selfEsteem", 
        "selfishness", 
        "social", 
        "social_clever", 
        "social_warm", 
        "state", 
        "strength", 
        "support_you", 
        "swarm", 
        "truth", 
        "will", 
        "oldFail", 
        "slowWork", 
        "stupid", 
        "dreamDeath", 
        "workWin", 
        "oddity", 
        "distract", 
        "youInfo", 
        "partnerInfo"
    ], 
    "fadingMemory": [], 
    "instantEmotionResource": [
        "complimentSwarm", 
        "complimentFlat", 
        "criticismSwarm", 
        "criticismFlat", 
        "oldFailSwarm", 
        "oldFailFlat", 
        "slowWorkSwarm", 
        "slowWorkFlat", 
        "viceFlatHim", 
        "dreamDeathMajor", 
        "workWinMajor", 
        "interruptionSwarm", 
        "insecureSwarmHim", 
        "workHappy", 
        "talkHappy", 
        "guiltEmoFlat", 
        "aloneFlatHim", 
        "casualSwarmHim", 
        "casualMedHim", 
        "tiredSwarmHim", 
        "worthlessHim", 
        "stupidityFlat"
    ], 
    "randomReplace": [
        "completeWorkResult", 
        "spendTimeResult", 
        "flirtResult", 
        "findUsefulResult", 
        "tryNewResult", 
        "exploreNewResult", 
        "findHelpResult", 
        "learnHimResult", 
        "findLifeHelpResult", 
        "sharePainResult", 
        "feedCrisisResult"
    ], 
    "emotionResourceMap": [
        "angerMap", 
        "joyMap", 
        "sadnessMap"
    ], 
    "memoryGoalButton": [], 
    "disableTrait": [
        "disableHim"
    ], 
    "placedTower": [
        "busyWorkPlaced", 
        "callousnessTowerPlaced", 
        "toughTowerPlaced", 
        "insecureMinePlaced", 
        "calmnessTowerPlaced", 
        "takeSupportTowerPlaced", 
        "mistrustJoyPlaced", 
        "selfValuePlaced"
    ], 
    "conditionalMake": [], 
    "gameStage": [
        "chapter1"
    ], 
    "creep": [
        "anger", 
        "joy", 
        "sadness", 
        "complimentSmall", 
        "complimentMed", 
        "workWinSmall", 
        "workWinLarge", 
        "viceMed", 
        "criticismSmall", 
        "criticismMed", 
        "aloneSmall", 
        "aloneMed", 
        "oldFailSmall", 
        "oldFailMed", 
        "slowWorkSmall", 
        "slowWorkMed", 
        "stupidityMed", 
        "dreamDeathLarge", 
        "interruptSmall", 
        "insecureSmall", 
        "guiltMed", 
        "casualSmall", 
        "casualMed", 
        "tiredSmall", 
        "worthlessSmall", 
        "worthlessMed", 
        "resentMed"
    ], 
    "killCurrency": [], 
    "personCurrencyAction": [], 
    "clearTrait": [
        "clearNewRelationship"
    ], 
    "flagBranch": [
        "connectHurtBranch", 
        "beSupportedBranch", 
        "takeConnectBranch", 
        "reachOutBranch", 
        "openUpBranch", 
        "relationBranch", 
        "youRelationButtonBranch", 
        "himRelationButtonBranch", 
        "defineRoleBranch"
    ], 
    "setFlag": [
        "setRelation", 
        "setYouRelation", 
        "setHimRelation", 
        "setDefineRoleDone"
    ], 
    "person": [], 
    "helpInfoPanel": [
        "towerHelpInfoPanel", 
        "goalHelpInfoPanel", 
        "traitHelpInfoPanel", 
        "trainPathHelpInfoPanel", 
        "dailyHelpInfoPanel"
    ], 
    "checkQuality": [], 
    "transformExec": [
        "restlessToHisWork", 
        "hisWorkToHisGoodWork", 
        "hisWorkToHisBadWork", 
        "hisGoodWorkToRestless", 
        "hisBadWorkToRestless", 
        "insecurityToCruelty", 
        "crueltyToInsecurity", 
        "newRelationshipToRelationship", 
        "insecurityToSearchingWorth", 
        "worthlessToInsecurity", 
        "searchingWorthToInsecurity", 
        "helpfulToInsecurity", 
        "searchingWorthToHelpful", 
        "hisGoodWorkToHisWork", 
        "hisBadWorkToFaithCrisis", 
        "hisBadWorkToHisWork"
    ], 
    "currencyOverload": [], 
    "pairTransform": [
        "flipMature", 
        "flipHurt", 
        "flipGood", 
        "flipClever"
    ], 
    "towerTickModifier": [], 
    "swallowOpinion": [], 
    "source": [
        "self", 
        "himself"
    ], 
    "memoryTower": [
        "supportTower", 
        "needPainTower", 
        "rechargeTower"
    ], 
    "memory": [
        "memory_shameBurst", 
        "memory_oldHurt", 
        "memory_sadAttack", 
        "memory_jealousyBurst", 
        "memory_joyBurst", 
        "memory_oldLife", 
        "memory_worthlessFeel", 
        "memory_viceFlatYou", 
        "memory_complimentSwarmYou", 
        "memory_complimentFlatYou", 
        "memory_criticismSwarmYou", 
        "memory_insecureSwarmYou", 
        "memory_guiltFlatYou", 
        "memory_aloneFlatYou", 
        "memory_casualSwarmYou", 
        "memory_resentYou"
    ], 
    "makeRandomMultiple": [], 
    "entityReplace": [
        "startPaths", 
        "himEntities", 
        "goodSpendTimeResult", 
        "completeWorkFull"
    ], 
    "qualityImprovement": [], 
    "endGoal": [
        "connectHurtDone", 
        "beSupportedDone", 
        "takeConnectDone", 
        "reachOutDone", 
        "openUpDone"
    ], 
    "personGoalButton": [], 
    "upgradeButton": [], 
    "menuModifier": [
        "explainSpendTimeFail", 
        "explainFindUsefulFail", 
        "explainFindHelpFail", 
        "explainLearnHimFail", 
        "explainFeedCrisisFail"
    ], 
    "emotionResource": [
        "shameBurstMine", 
        "oldHurtMine", 
        "sadAttackMine", 
        "jealousyBurstMine", 
        "joyBurstMine", 
        "oldLifeMine", 
        "worthlessFeelMine", 
        "viceFlatYouMine", 
        "complimentSwarmYouMine", 
        "complimentFlatYouMine", 
        "criticismSwarmYouMine", 
        "insecureSwarmYouMine", 
        "guiltFlatYouMine", 
        "aloneFlatYouMine", 
        "casualSwarmYouMine", 
        "resentYouMine", 
        "flashback_oldFailSmall", 
        "flashback_oldFailMed", 
        "flashback_complimentMed", 
        "flashback_guiltMed", 
        "flashback_joy", 
        "flashback_worthlessMed", 
        "flashback_aloneMed", 
        "flashback_complimentSmall", 
        "flashback_viceMed", 
        "flashback_sadness", 
        "flashback_casualSmall", 
        "flashback_worthlessSmall", 
        "flashback_anger", 
        "flashback_criticismSmall", 
        "flashback_insecureSmall", 
        "flashback_resentMed"
    ], 
    "resourceButton": [
        "anxietyMineButton", 
        "flirtationMineButton", 
        "thinkMineButton", 
        "socialMineButton", 
        "calmnessMineButton", 
        "strengthMineButton", 
        "willMineButton", 
        "meditativeMineButton", 
        "socialWarmMineButton", 
        "socialCleverMineButton", 
        "relationshipMineButton", 
        "goodnessMineButton", 
        "selfishnessMineButton", 
        "oldFailMineButton"
    ], 
    "flaggedMake": [], 
    "makeAll": [
        "makeAllPathMaker"
    ], 
    "dailyEntityMaker": [
        "choreMaker", 
        "whatsNewMaker"
    ], 
    "currencyAction": [
        "selfDistractionAction", 
        "obsessionsAction", 
        "flirtAction", 
        "pushAction", 
        "solveProbeAction", 
        "selfValueAction", 
        "callousnessAction", 
        "opennessAction", 
        "mistrustJoyAction", 
        "socialAction", 
        "helpValueAction", 
        "needPainAction", 
        "needBusyAction", 
        "supportNeedAction", 
        "toughAction", 
        "obsessHimAction", 
        "rechargeAction", 
        "takeSupportAction", 
        "busyWorkAction", 
        "calmnessAction", 
        "shareJoyAction", 
        "applyAction", 
        "friendMeditateAction", 
        "truthAction", 
        "supportAction", 
        "himSupportAction", 
        "sympathyAction", 
        "caringAction", 
        "swarmAction", 
        "stateAction", 
        "complimentAction", 
        "generousAction", 
        "criticismAction", 
        "crueltyAction", 
        "viceAction", 
        "majorAction", 
        "distractAction"
    ], 
    "timedFocusHolder": [], 
    "personTowerButton": [], 
    "entityKill": [
        "killFaithCrisis", 
        "killWork", 
        "killStartRelationYouButton", 
        "killStartRelationHimButton", 
        "killConnectFriendsButton", 
        "killDefineRoleButton", 
        "killCapable"
    ], 
    "emotionSource": [
        "shameBurst", 
        "oldHurt", 
        "sadAttack", 
        "jealousyBurst", 
        "joyBurst", 
        "oldLife", 
        "worthlessFeel", 
        "viceFlatYou", 
        "complimentSwarmYou", 
        "complimentFlatYou", 
        "criticismSwarmYou", 
        "insecureSwarmYou", 
        "guiltFlatYou", 
        "aloneFlatYou", 
        "casualSwarmYou", 
        "resentYou"
    ], 
    "gainControlMenu": [
        "gainControl_anger", 
        "gainControl_joy", 
        "gainControl_sadness"
    ], 
    "personResource": [], 
    "gameStageStartMenu": [], 
    "memoryConstruction": [
        "cheerMineConstruction", 
        "supportTowerConstruction", 
        "needPainTowerConstruction", 
        "rechargeTowerConstruction"
    ], 
    "trait": [
        "you", 
        "worthless", 
        "insecurity", 
        "critical", 
        "searchingWorth", 
        "helpful", 
        "restLife", 
        "him", 
        "restless", 
        "hisWork", 
        "faithCrisis", 
        "hisGoodWork", 
        "hisBadWork", 
        "capable", 
        "newRelationship", 
        "relationship", 
        "conversation", 
        "good", 
        "selfish", 
        "warm", 
        "clever", 
        "hurting", 
        "strong", 
        "tempTrait"
    ], 
    "defineRole": [
        "role"
    ], 
    "goalButton": [
        "obsessButton", 
        "becomeCriticalButton", 
        "criticizeSelfButton", 
        "startRelationYouButton", 
        "startRelationHimButton", 
        "tryForConnectionYouButton", 
        "tryForConnectionHimButton", 
        "flirtYouButton", 
        "flirtHimButton", 
        "connectFriendsButton", 
        "forceOpennessButton", 
        "quietTimeButton", 
        "pushInsecurityButton", 
        "triggerCrisisButton", 
        "searchWorthButton", 
        "defineRoleButton", 
        "findUsefulButton", 
        "accuseSelfishButton", 
        "askHelpButton", 
        "acceptMeanlessButton", 
        "rejectMeanlessButton", 
        "tryNewButton", 
        "findHelpButton", 
        "feelUselessButton", 
        "winButton", 
        "startConverseButton", 
        "appreciateWorkButton", 
        "deriveWorkTopicButton", 
        "askAboutRestlessButton", 
        "talkAboutHimButton", 
        "talkAboutYouButton", 
        "needHelpButton", 
        "guiltButton", 
        "talkInterestingButton", 
        "fascinateButton", 
        "defineHelpButton", 
        "hardWorkButton", 
        "completeWorkButton", 
        "learnHimButton", 
        "getFeedbackButton", 
        "sharePainButton", 
        "overcomeHurtButton", 
        "calmPartnerButton", 
        "overcomeCrisisButton", 
        "feedCrisisButton", 
        "supportCrisisButton", 
        "connectHurtButton", 
        "beSupportedButton", 
        "diveHurtButton", 
        "exploreStrengthButton", 
        "giveInButton", 
        "reachOutButton", 
        "takeConnectButton", 
        "openUpButton", 
        "spendTimeButton", 
        "makeComplimentSwarmButton", 
        "makeComplimentFlatButton", 
        "makeCriticismSwarmButton", 
        "makeCriticismFlatButton", 
        "makeOldFailSwarmButton", 
        "makeOldFailFlatButton", 
        "makeSlowWorkSwarmButton", 
        "makeSlowWorkFlatButton", 
        "makeStupidityFlatButton", 
        "makeDreamDeathMajorButton", 
        "makeWorkWinMajorButton", 
        "trySomethingButton", 
        "complimentYouButton", 
        "speakOfValueButton", 
        "takeOutFrustrationButton", 
        "askForBeliefButton", 
        "spendTimeWarmButton", 
        "spendTimeCleverButton", 
        "indulgeViceButton", 
        "getOverBadWorkButton", 
        "getOverGoodWorkButton", 
        "fishComplimentsButton"
    ], 
    "resource": [
        "anxietyMine", 
        "flirtationMine", 
        "thinkMine", 
        "calmnessMine", 
        "strengthMine", 
        "willMine", 
        "meditativeMine", 
        "socialWarmMine", 
        "socialCleverMine", 
        "busyWorkMine", 
        "insecureMine", 
        "relationshipMine", 
        "goodnessMine", 
        "selfishnessMine", 
        "socialMine", 
        "oldFailMine"
    ], 
    "towerButton": [
        "callousnessButton", 
        "calmnessButton", 
        "caringButton", 
        "complimentButton", 
        "criticismButton", 
        "crueltyButton", 
        "distractButton", 
        "flirtButton", 
        "friendMeditateButton", 
        "generousButton", 
        "helpValueButton", 
        "himSupportButton", 
        "majorButton", 
        "mistrustJoyButton", 
        "needBusyButton", 
        "obsessHimButton", 
        "obsessionsButton", 
        "opennessButton", 
        "pushButton", 
        "selfDistractionButton", 
        "selfValueButton", 
        "shareJoyButton", 
        "socialButton", 
        "solveProbeButton", 
        "stateButton", 
        "supportNeedButton", 
        "swarmButton", 
        "takeSupportButton", 
        "toughButton", 
        "truthButton", 
        "viceButton"
    ], 
    "traitParticleEffect": [
        "newTraitParticle"
    ], 
    "opinion": [], 
    "memoryResource": [
        "frustrationMine", 
        "painMine", 
        "cheerMine"
    ], 
    "memoryGoal": [], 
    "worldGoalParticleEffect": [
        "newParticle"
    ], 
    "timedCreateEntities": [], 
    "memoryResourceButton": [
        "cheerMineButton"
    ], 
    "switch": [
        "switchHelpGoal", 
        "switchValueDeposit", 
        "switchFascinateButton", 
        "switchCalmnessDeposit", 
        "switchTriggerCrisisButton", 
        "switchFeedCrisisButton", 
        "switchSupportCrisisButton", 
        "switchThankGoal", 
        "switchYouInfoDeposit"
    ], 
    "construction": [
        "anxietyMineConstruction", 
        "flirtationMineConstruction", 
        "thinkMineConstruction", 
        "socialMineConstruction", 
        "calmnessMineConstruction", 
        "strengthMineConstruction", 
        "willMineConstruction", 
        "meditativeMineConstruction", 
        "socialWarmMineConstruction", 
        "socialCleverMineConstruction", 
        "relationshipMineConstruction", 
        "goodnessMineConstruction", 
        "selfishnessMineConstruction", 
        "oldFailMineConstruction", 
        "callousnessTowerConstruction", 
        "calmnessTowerConstruction", 
        "caringTowerConstruction", 
        "complimentTowerConstruction", 
        "criticismTowerConstruction", 
        "crueltyTowerConstruction", 
        "distractTowerConstruction", 
        "flirtTowerConstruction", 
        "friendMeditateTowerConstruction", 
        "generousTowerConstruction", 
        "helpValueTowerConstruction", 
        "himSupportTowerConstruction", 
        "majorTowerConstruction", 
        "mistrustJoyTowerConstruction", 
        "needBusyTowerConstruction", 
        "obsessHimTowerConstruction", 
        "obsessionsTowerConstruction", 
        "opennessTowerConstruction", 
        "pushTowerConstruction", 
        "selfDistractionTowerConstruction", 
        "selfValueTowerConstruction", 
        "shareJoyTowerConstruction", 
        "socialTowerConstruction", 
        "solveProbeTowerConstruction", 
        "stateTowerConstruction", 
        "supportNeedTowerConstruction", 
        "swarmTowerConstruction", 
        "takeSupportTowerConstruction", 
        "toughTowerConstruction", 
        "truthTowerConstruction", 
        "viceTowerConstruction", 
        "obsessGoalConstruction", 
        "becomeCriticalGoalConstruction", 
        "criticizeSelfGoalConstruction", 
        "startRelationYouGoalConstruction", 
        "startRelationHimGoalConstruction", 
        "tryForConnectionYouGoalConstruction", 
        "tryForConnectionHimGoalConstruction", 
        "flirtYouGoalConstruction", 
        "flirtHimGoalConstruction", 
        "connectFriendsGoalConstruction", 
        "forceOpennessGoalConstruction", 
        "quietTimeGoalConstruction", 
        "pushInsecurityGoalConstruction", 
        "triggerCrisisGoalConstruction", 
        "searchWorthGoalConstruction", 
        "defineRoleGoalConstruction", 
        "findUsefulGoalConstruction", 
        "accuseSelfishGoalConstruction", 
        "askHelpGoalConstruction", 
        "acceptMeanlessGoalConstruction", 
        "rejectMeanlessGoalConstruction", 
        "tryNewGoalConstruction", 
        "findHelpGoalConstruction", 
        "feelUselessGoalConstruction", 
        "winGoalConstruction", 
        "startConverseGoalConstruction", 
        "appreciateWorkGoalConstruction", 
        "deriveWorkTopicGoalConstruction", 
        "askAboutRestlessGoalConstruction", 
        "talkAboutHimGoalConstruction", 
        "talkAboutYouGoalConstruction", 
        "needHelpGoalConstruction", 
        "guiltGoalConstruction", 
        "talkInterestingGoalConstruction", 
        "fascinateGoalConstruction", 
        "defineHelpGoalConstruction", 
        "hardWorkGoalConstruction", 
        "completeWorkGoalConstruction", 
        "learnHimGoalConstruction", 
        "getFeedbackGoalConstruction", 
        "sharePainGoalConstruction", 
        "overcomeHurtGoalConstruction", 
        "calmPartnerGoalConstruction", 
        "overcomeCrisisGoalConstruction", 
        "feedCrisisGoalConstruction", 
        "supportCrisisGoalConstruction", 
        "connectHurtGoalConstruction", 
        "beSupportedGoalConstruction", 
        "diveHurtGoalConstruction", 
        "exploreStrengthGoalConstruction", 
        "giveInGoalConstruction", 
        "reachOutGoalConstruction", 
        "takeConnectGoalConstruction", 
        "openUpGoalConstruction", 
        "spendTimeGoalConstruction", 
        "makeComplimentSwarmGoalConstruction", 
        "makeComplimentFlatGoalConstruction", 
        "makeCriticismSwarmGoalConstruction", 
        "makeCriticismFlatGoalConstruction", 
        "makeOldFailSwarmGoalConstruction", 
        "makeOldFailFlatGoalConstruction", 
        "makeSlowWorkSwarmGoalConstruction", 
        "makeSlowWorkFlatGoalConstruction", 
        "makeStupidityFlatGoalConstruction", 
        "makeDreamDeathMajorGoalConstruction", 
        "makeWorkWinMajorGoalConstruction", 
        "trySomethingGoalConstruction", 
        "complimentYouGoalConstruction", 
        "speakOfValueGoalConstruction", 
        "takeOutFrustrationGoalConstruction", 
        "askForBeliefGoalConstruction", 
        "spendTimeWarmGoalConstruction", 
        "spendTimeCleverGoalConstruction", 
        "indulgeViceGoalConstruction", 
        "getOverBadWorkGoalConstruction", 
        "getOverGoodWorkGoalConstruction", 
        "fishComplimentsGoalConstruction"
    ], 
    "damageUpgrade": [], 
    "deposit": [
        "opennessDeposit", 
        "obsessionDeposit", 
        "goodWorkDeposit", 
        "completeWorkDeposit", 
        "hisValueDeposit", 
        "slowWorkDeposit", 
        "stupidDeposit", 
        "dreamDeathDeposit", 
        "workWinDeposit", 
        "oddityDeposit", 
        "busyWorkDeposit", 
        "selfEsteemDeposit", 
        "strengthDeposit", 
        "youInfoDeposit", 
        "partnerInfoDeposit", 
        "calmnessDeposit", 
        "topicDeposit", 
        "probedProblemDeposit", 
        "valueDeposit", 
        "largeValueDeposit", 
        "helpDeposit", 
        "workTopicDeposit", 
        "interestingDeposit", 
        "hisEmotionDeposit"
    ], 
    "nextDayEntity": [], 
    "pathMaker": [
        "selfPathYou", 
        "youPathInsecurity", 
        "insecurityPathFun", 
        "insecurityPathWarm", 
        "funPathHurting", 
        "hurtingPathRelationship", 
        "warmPathRelationship", 
        "warmPathSelfish", 
        "warmPathYou", 
        "selfishPathRelationship", 
        "relationshipPathStrong", 
        "relationshipPathGood", 
        "goodPathClever", 
        "strongPathMature", 
        "maturePathHisWork", 
        "cleverPathRestless", 
        "worthlessPathNewRelationship", 
        "relationshipPathHisWork", 
        "restlessPathStrong", 
        "insecurePathHurting", 
        "hurtingPathClever", 
        "cleverPathRelationship", 
        "himPathHimself", 
        "insecurityPathNewRelationship", 
        "restlessPathNewRelationship", 
        "goodPathYou", 
        "goodPathRelationship", 
        "selfishPathHim", 
        "funPathYou", 
        "funPathRelationship", 
        "disciplinePathHim"
    ], 
    "tower": [
        "busyWorkTower", 
        "callousnessTower", 
        "calmnessTower", 
        "caringTower", 
        "complimentTower", 
        "criticismTower", 
        "crueltyTower", 
        "distractTower", 
        "flirtTower", 
        "friendMeditateTower", 
        "generousTower", 
        "helpValueTower", 
        "himSupportTower", 
        "majorTower", 
        "mistrustJoyTower", 
        "needBusyTower", 
        "obsessHimTower", 
        "obsessionsTower", 
        "opennessTower", 
        "pushTower", 
        "selfDistractionTower", 
        "selfValueTower", 
        "shareJoyTower", 
        "socialTower", 
        "solveProbeTower", 
        "stateTower", 
        "supportNeedTower", 
        "swarmTower", 
        "takeSupportTower", 
        "toughTower", 
        "truthTower", 
        "viceTower"
    ], 
    "personResourceButton": [], 
    "personCurrency": [], 
    "personTower": [], 
    "emotionSourceConstruction": [
        "shameBurstMineConstruction", 
        "oldHurtMineConstruction", 
        "sadAttackMineConstruction", 
        "jealousyBurstMineConstruction", 
        "joyBurstMineConstruction", 
        "oldLifeMineConstruction", 
        "worthlessFeelMineConstruction", 
        "viceFlatYouMineConstruction", 
        "complimentSwarmYouMineConstruction", 
        "complimentFlatYouMineConstruction", 
        "criticismSwarmYouMineConstruction", 
        "insecureSwarmYouMineConstruction", 
        "guiltFlatYouMineConstruction", 
        "aloneFlatYouMineConstruction", 
        "casualSwarmYouMineConstruction", 
        "resentYouMineConstruction", 
        "flashback_oldFailSmallConstruction", 
        "flashback_oldFailMedConstruction", 
        "flashback_complimentMedConstruction", 
        "flashback_guiltMedConstruction", 
        "flashback_joyConstruction", 
        "flashback_worthlessMedConstruction", 
        "flashback_aloneMedConstruction", 
        "flashback_complimentSmallConstruction", 
        "flashback_viceMedConstruction", 
        "flashback_sadnessConstruction", 
        "flashback_casualSmallConstruction", 
        "flashback_worthlessSmallConstruction", 
        "flashback_angerConstruction", 
        "flashback_criticismSmallConstruction", 
        "flashback_insecureSmallConstruction", 
        "flashback_resentMedConstruction"
    ], 
    "memoryTowerButton": [
        "supportButton", 
        "needPainButton", 
        "rechargeButton"
    ]
}

var findKeyFor = function(csvId, key, val){
    return _.chain(csvIdentifiers[csvId])
    .filter(function(argKey){
        return (allArgs[argKey][key] == val);
    })
    .first()
    .value();
};

var updateArgs = function(args, defaultArgs){
    _.each(defaultArgs, function(val, key){
        args[key] = val;
    });
};

var uidManager = (function(){
    var uid = 0;
    return {
        getUid: function(){
            uid += 1;
            return uid;
        },
        setUid: function(newUid){
            uid = newUid;
        }
    };
})();

var makeEcs = function(key, args){
    if (ecs[key] === undefined){
        console.log('tried to build ' + key);
    }

    args = (args === undefined) ? {} : args;
    if (!args.uid){
        args.uid = uidManager.getUid();
    }
    
    var passedArgs = _.clone(args);
    
    var newEcs = ecs[key](args);
    
    newEcs.key = key;
    newEcs.passedArgs = passedArgs;
    newEcs.uid = args.uid;

    return newEcs;
};

var makeAllEcs = function(csvId){
    return _.map(csvIdentifiers[csvId], function(key){
        return makeEcs(key, {});
    });
};
