diff --git a/add_missing_mss.py b/add_missing_mss.py
deleted file mode 100644
index 7d8459d..0000000
--- a/add_missing_mss.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from util import dataUtil, newUserObjectUtil
-
-allSectionIds = dataUtil.masterSections.keys()
-userSectionIds = dataUtil.userIndices['userSectionList'].keys()
-userCharaIds = dataUtil.userIndices['userCharaList'].keys()
-missingMSSections = [sectionId for sectionId in allSectionIds if not sectionId in userSectionIds and str(sectionId).startswith('3')]
-addSections = [sectionId for sectionId in missingMSSections if int(str(sectionId)[1:5]) in userCharaIds]
-userSectionList = dataUtil.readJson('data/user/userSectionList.json')
-for sectionId in addSections:
-    userSection = {
-        "userId": dataUtil.userId,
-        "sectionId": sectionId,
-        "section": dataUtil.masterSections[sectionId],
-        "canPlay": True, #str(sectionId).endswith('1'),
-        "cleared": False,
-        "createdAt": newUserObjectUtil.nowstr()
-    }
-    userSectionList.append(userSection)
-dataUtil.saveJson('data/user/userSectionList.json', userSectionList)
-
-allBattleIds = dataUtil.masterBattles.keys()
-userBattleIds = dataUtil.userIndices['userQuestBattleList'].keys()
-missingMSSBattles = [battleId for battleId in allBattleIds if not battleId in userBattleIds and str(battleId).startswith('3')]
-addBattles = [battleId for battleId in missingMSSBattles if int(str(battleId)[1:5]) in userCharaIds]
-userQuestBattleList = dataUtil.readJson('data/user/userQuestBattleList.json')
-for battleId in addBattles:
-    userBattle = {
-        "userId": dataUtil.userId,
-        "questBattleId": battleId,
-        "questBattle": dataUtil.masterBattles[battleId],
-        "cleared": False,
-        "missionStatus1": "NON_CLEAR",
-        "missionStatus2": "NON_CLEAR",
-        "missionStatus3": "NON_CLEAR",
-        "rewardDone": False,
-        "createdAt": newUserObjectUtil.nowstr()
-    }
-    userQuestBattleList.append(userBattle)
-dataUtil.saveJson('data/user/userQuestBattleList.json', userQuestBattleList)
\ No newline at end of file
diff --git a/api/gacha.py b/api/gacha.py
index ea7b7d2..b11bbb8 100644
--- a/api/gacha.py
+++ b/api/gacha.py
@@ -151,6 +151,47 @@ def addGem(gem):
     dataUtil.setUserObject('userItemList', gem['itemCode'], item)
     return item
 
+def addStory(charaId):
+    existingSections = dataUtil.listUserObjectKeys('userSectionList')
+    validSections = dataUtil.masterSections.keys()
+    userSectionDict = {}
+    for i in range(4):
+        sectionId = '3{0}{1}'.format(charaId, i+1)
+        if sectionId in existingSections: continue
+        if sectionId in validSections:
+            userSectionDict[sectionId] = {
+                "userId": dataUtil.userId,
+                "sectionId": sectionId,
+                "section": dataUtil.masterSections[sectionId],
+                "canPlay": True, #str(sectionId).endswith('1'),
+                "cleared": False,
+                "createdAt": newUserObjectUtil.nowstr()
+            }
+
+    existingBattles = dataUtil.listUserObjectKeys('userQuestBattleList')
+    validBattles = dataUtil.masterBattles.keys()
+    userQuestBattleDict = {}
+    for i in range(4):
+        for j in range(3):
+            battleId = '3{0}{1}{2}'.format(charaId, i+1, j+1)
+            if battleId in existingBattles: continue
+            if battleId in validBattles:
+                userQuestBattleDict[battleId] = {
+                    "userId": dataUtil.userId,
+                    "questBattleId": battleId,
+                    "questBattle": dataUtil.masterBattles[battleId],
+                    "cleared": True,
+                    "missionStatus1": "CLEARED",
+                    "missionStatus2": "CLEARED",
+                    "missionStatus3": "CLEARED",
+                    "rewardDone": True,
+                    "createdAt": newUserObjectUtil.nowstr()
+                }
+    
+    dataUtil.batchSetUserObject('userSectionList', userSectionDict)
+    dataUtil.batchSetUserObject('userQuestBattleList', userQuestBattleDict)
+    return list(userSectionDict.values()), list(userQuestBattleDict.values())
+
 def addMeguca(charaId):
     # TODO: get the story of the meguca
     userChara = dataUtil.getUserObject('userCharaList', charaId)
@@ -165,7 +206,7 @@ def addMeguca(charaId):
         dataUtil.saveJson('data/user/userLive2dList.json', dataUtil.readJson(live2dPath) + [userLive2d])
     else:
         userChara['lbItemNum'] += 1
-        dataUtil.setUserObject('userCharaList', userChara['userCardId'], userChara)
+        dataUtil.setUserObject('userCharaList', charaId, userChara)
 
         userCard = dataUtil.getUserObject('userCardList', userChara['userCardId'])
         userLive2d = dataUtil.getUserObject('userLive2dList', int(str(charaId)+'00'))
@@ -189,7 +230,6 @@ def addPiece(pieceId):
     
 def draw():
     # TODO: give a destiny gem if there's a dupe in the same multi-pull
-    # TODO: get stories
 
     # handle different types of gachas
     body = flask.request.json
@@ -233,6 +273,8 @@ def draw():
     userPieceList = []
     userLive2dList = []
     userItemList = []
+    userSectionList = None
+    userQuestBattleList = None
 
     responseList = []
 
@@ -252,6 +294,7 @@ def draw():
             if not foundExisting:
                 userCardList.append(card)
                 userLive2dList.append(live2d)
+                userSectionList, userQuestBattleList = addStory(result['charaId'])
             userCharaList.append(chara)
             directionType = 3
             if result['cardList'][0]['card']['rank'][-1] == "4":
@@ -355,6 +398,9 @@ def draw():
         "userPieceList": userPieceList
     }
 
+    if userSectionList is not None: response['userSectionList'] = userSectionList
+    if userQuestBattleList is not None: response['userQuestBattleList'] = userQuestBattleList
+
     # add to user history
     pullId = str(uuid1())
     if not os.path.exists('data/user/gachaHistory'):
diff --git a/api/shop.py b/api/shop.py
index e526d1c..9ad4881 100644
--- a/api/shop.py
+++ b/api/shop.py
@@ -8,8 +8,15 @@
 
 # This will only get you the lowest rarity card, but that's what all shop megucas have been...
 def getCard(charaNo):
-    userCard, userChara, userLive2d, _ = gacha.addMeguca(charaNo)
-    return {'userCardList': [userCard], 'userCharaList': [userChara], 'userLive2dList': [userLive2d]}
+    userCard, userChara, userLive2d, foundExisting = gacha.addMeguca(charaNo)
+    response = {'userCardList': [userCard], 'userCharaList': [userChara], 'userLive2dList': [userLive2d]}
+
+    if not foundExisting:
+        userSectionList, userQuestBattleList = gacha.addStory(charaNo)
+        response['userSectionList'] = userSectionList
+        response['userQuestBattleList'] = userQuestBattleList
+        
+    return response
 
 def getFormation(formationId):
     userFormation, exists = newUserObjectUtil.createUserFormation(formationId)
@@ -92,7 +99,7 @@ def obtain(item, body, args):
     elif item['shopItemType'] == 'FORMATION_SHEET':
         args.update(getFormation(item['formationSheet']['id']))
     elif item['shopItemType'] == 'GEM':
-        args.update(getGems(item['genericId'], body['num']))
+        args.update(getGems(int(item['genericId']), body['num']))
     elif item['shopItemType'] == 'GIFT':
         newGifts = getGift(int(item['gift']['rewardCode'].split('_')[1]), body['num']*int(item['rewardCode'].split('_')[-1]))
         args['userGiftList'] = args.get('userGiftList', []) + newGifts['userGiftList']
diff --git a/charaTools.py b/charaTools.py
new file mode 100644
index 0000000..ce19d41
--- /dev/null
+++ b/charaTools.py
@@ -0,0 +1,98 @@
+from util import dataUtil, newUserObjectUtil
+import json
+
+def addMissingMss():
+    allSectionIds = dataUtil.masterSections.keys()
+    userSectionIds = dataUtil.userIndices['userSectionList'].keys()
+    userCharaIds = dataUtil.userIndices['userCharaList'].keys() # don't need to dedupe because this already is a set
+    missingMSSections = [sectionId for sectionId in allSectionIds if not sectionId in userSectionIds and str(sectionId).startswith('3')]
+    addSections = [sectionId for sectionId in missingMSSections if int(str(sectionId)[1:5]) in userCharaIds]
+    userSectionList = dataUtil.readJson('data/user/userSectionList.json')
+    for sectionId in addSections:
+        userSection = {
+            "userId": dataUtil.userId,
+            "sectionId": sectionId,
+            "section": dataUtil.masterSections[sectionId],
+            "canPlay": True, #str(sectionId).endswith('1'),
+            "cleared": False,
+            "createdAt": newUserObjectUtil.nowstr()
+        }
+        userSectionList.append(userSection)
+    dataUtil.saveJson('data/user/userSectionList.json', userSectionList)
+
+    allBattleIds = dataUtil.masterBattles.keys()
+    userBattleIds = dataUtil.userIndices['userQuestBattleList'].keys()
+    missingMSSBattles = [battleId for battleId in allBattleIds if not battleId in userBattleIds and str(battleId).startswith('3')]
+    addBattles = [battleId for battleId in missingMSSBattles if int(str(battleId)[1:5]) in userCharaIds]
+    userQuestBattleList = dataUtil.readJson('data/user/userQuestBattleList.json')
+    for battleId in addBattles:
+        userBattle = {
+            "userId": dataUtil.userId,
+            "questBattleId": battleId,
+            "questBattle": dataUtil.masterBattles[battleId],
+            "cleared": True,
+            "missionStatus1": "CLEARED",
+            "missionStatus2": "CLEARED",
+            "missionStatus3": "CLEARED",
+            "rewardDone": True,
+            "createdAt": newUserObjectUtil.nowstr()
+        }
+        userQuestBattleList.append(userBattle)
+    dataUtil.saveJson('data/user/userQuestBattleList.json', userQuestBattleList)
+
+def dedupeCharas():
+    # the problem is, every time you pull a new copy, you get a new chara
+    # but until the end of the session, the game is stuck on the first chara
+    # so we take the max episode point, and lbItemNum of the last chara
+    # this leaves off some episode points that were earned, but might refund some gems
+    finalCharas = {}
+    with open('data/user/userCharaList.json', encoding='utf-8') as f:
+        userCharaList = json.load(f)
+    for userChara in userCharaList:
+        charaId = userChara['charaId']
+        if charaId in finalCharas:
+            finalCharas[charaId]['bondsTotalPt'] = max(finalCharas[charaId]['bondsTotalPt'], userChara['bondsTotalPt'])
+            finalCharas[charaId]['lbItemNum'] = userChara['lbItemNum']
+        else:
+            finalCharas[charaId] = userChara
+
+    with open('data/user/userCharaList.json', 'w+', encoding='utf-8') as f:
+        json.dump(list(finalCharas.values()), f, ensure_ascii=False)
+
+if __name__=='__main__':
+    print(
+"""
+My, are you here for an adjustment?
+
+Which would you like today?
+1) Add MSS for characters you've pulled
+2) Get rid of extra MSS
+3) N-nothing, just wanted to...visit...
+"""
+    )
+    while True:
+        choice = input('(type 1, 2, or 3, then enter): ')
+        if choice == '1':
+            addMissingMss()
+            print('Here you go.')
+        if choice == '2':
+            dedupeCharas()
+            print('Done. Oh, I might have accidentally touched some other bits of your fate, like giving you extra destiny gems -- but that shouldn\'t bother you too much.')
+        if choice == '3':
+            print()
+            print('Ooh, I\'m flattered. I\'ll always be here when you need me for adjustment, \'kay?')
+            input('(enter to close)')
+            exit(0)
+        print()
+
+        print('Is that all for today?')
+        while(True):
+            choice = input('(Y/N): ')
+            if choice.lower() == 'y':
+                print()
+                print('Thanks, come again!')
+                input('(enter to close)')
+                exit(0)
+            if choice.lower() == 'n':
+                break
+            print('Sorry, what was that?')
\ No newline at end of file
diff --git a/util/dataUtil.py b/util/dataUtil.py
index 9cdb7db..f731124 100644
--- a/util/dataUtil.py
+++ b/util/dataUtil.py
@@ -46,9 +46,9 @@ def createIndexFromList(xs, idFunc=idxFunc('id'), valFunc=INDEX_VALFUNC):
     'userGiftList': createIndex('data/user/userGiftList.json', idxFunc('giftId')),
     'userItemList': createIndex('data/user/userItemList.json', idxFunc('itemId')),
     'userLimitedChallengeList': createIndex('data/user/userLimitedChallengeList.json', idxFunc('challengeId')),
-    'userLive2dList': createIndex('data/user/userLimitedChallengeList.json', 
+    'userLive2dList': createIndex('data/user/userLive2dList.json', 
                 lambda x: int(str(x['charaId'])+x['live2dId']), 
-                valFunc=ITEM_VALFUNC),
+                valFunc=INDEX_VALFUNC),
     'userPieceList': createIndex('data/user/userPieceList.json'),
     'userPieceCollectionList': createIndex('data/user/userPieceCollectionList.json', idxFunc('pieceId')),
     'userPieceSetList': createIndex('data/user/userPieceSetList.json', idxFunc('setNum')),
@@ -63,6 +63,9 @@ def createIndexFromList(xs, idFunc=idxFunc('id'), valFunc=INDEX_VALFUNC):
 # Doesn't work for userShopItemList, but we're having separate cases for that anyways
 userPaths = {key: 'data/user/'+key+'.json' for key in userIndices.keys()}
 
+def listUserObjectKeys(listName):
+    return set(userIndices[listName].keys())
+
 def deleteUserObject(listName, objectId):
     path = userPaths[listName]
     data = readJson(path)
@@ -100,6 +103,21 @@ def setUserObject(listName, objectId, objectData):
     saveJson(path, data)
     return data
 
+def batchSetUserObject(listName, objectDict):
+    path = userPaths[listName]
+    data = readJson(path)
+    
+    for objectId, objectData in objectDict.items():
+        if objectId in userIndices[listName]:
+            idx = userIndices[listName][objectId]
+            data[idx] = objectData
+        else:
+            userIndices[listName][objectId] = len(data)
+            data.append(objectData)
+    
+    saveJson(path, data)
+    return data
+
 def getGameUserValue(key):
     gameUser = readJson('data/user/gameUser.json')
     if not key in gameUser: