private void UpdateWorkCell <T>(int col, int row)
        {
            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }

            object val = dataGridView_noon_work_data[col, row].Value;

            if (val is bool)
            {
                val = !(bool)val;
            }

            int workID = rowToNoonWorkID[row];

            if (!updateWorkTable)
            {
                if (val is T)
                {
                    maid.SetWorkValue(workID, col, val);
                }
                else
                {
                    maid.UpdateWorkData(workID);
                }
            }
            updateWorkTable = false;
        }
        private void OnFeaturePropensityUpdated(object sender, UpdateFeaturePropensityEventArgs args)
        {
            Debugger.Assert(
                () =>
            {
                MaidInfo maid = SelectedMaid;
                if (maid == null)
                {
                    return;
                }

                if (args.CallerMaid != maid.Maid)
                {
                    return;
                }

                if (args.UpdateFeature)
                {
                    Debugger.WriteLine(LogLevel.Info, "Updating all features!");
                    for (Feature e = Feature.Null + 1; e < EnumHelper.MaxFeature; e++)
                    {
                        maid.UpdateMiscStatus(MaidChangeType.Feature, (int)e);
                    }
                }
                else if (args.UpdatePropensity)
                {
                    Debugger.WriteLine(LogLevel.Info, "Updating all propensities!");
                    for (Propensity e = Propensity.Null + 1; e < EnumHelper.MaxPropensity; e++)
                    {
                        maid.UpdateMiscStatus(MaidChangeType.Propensity, (int)e);
                    }
                }
            },
                "Failed to update maid features/propensities");
        }
Пример #3
0
        private void SetYotogiUsedTimes(object sender, EventArgs e)
        {
            uint       v;
            TextDialog td = new TextDialog(Translation.GetTranslation("GUI_YOTOGI_TIMES_TITLE"),
                                           Translation.GetTranslation("GUI_YOTOGI_TIMES_PROMPT"), "0",
                                           s => uint.TryParse(s, out v), Translation.GetTranslation("OK"),
                                           Translation.GetTranslation("CANCEL"))
            {
                StartPosition = FormStartPosition.CenterParent
            };
            DialogResult dr = td.ShowDialog(this);

            Debugger.WriteLine(LogLevel.Info, $"Prompt result: {EnumHelper.GetName(dr)}, {td.Input}");

            if (dr != DialogResult.OK)
            {
                return;
            }
            v = uint.Parse(td.Input);
            td.Dispose();

            MaidInfo maid = SelectedMaid;

            foreach (var skill in
                     Yotogi.skill_data_list.SelectMany(ee => ee).Where(ss => maid.Maid.Param.status.IsGetSkill(ss.Key)))
            {
                maid.Maid.Param.status_.skill_data[skill.Key].play_count = v;
                maid.UpdateSkillData(skill.Value.id);
            }
        }
        private void OnPropertyHasChanged(object sender, StatusChangedEventArgs args)
        {
            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }

            if (maid.Maid != args.CallerMaid)
            {
                return;
            }

            if (valueUpdateQueue[currentQueue].ContainsKey(args.Tag))
            {
                Debugger.WriteLine(LogLevel.Warning, $"Tag already in update queue {currentQueue}! Aborting...");
                return;
            }
            switch (args.Tag)
            {
            case MaidChangeType.NewGetWork:
            case MaidChangeType.Work:
                valueUpdateQueue[currentQueue].Add(args.Tag, () => maid.UpdateHasWork(args.ID));
                break;

            case MaidChangeType.NewGetSkill:
            case MaidChangeType.Skill:
                valueUpdateQueue[currentQueue].Add(args.Tag, () => maid.UpdateHasSkill(args.ID));
                break;
            }
        }
        private void OnStatusChanged(object sender, StatusChangedEventArgs args)
        {
            Debugger.WriteLine($"Changed status for property {EnumHelper.GetName(args.Tag)}");
            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                Debugger.WriteLine(LogLevel.Warning, "Maid is NULL!");
                return;
            }

            if (maid.Maid != args.CallerMaid)
            {
                Debugger.WriteLine(LogLevel.Warning, "Caller maid is not the selected one! Aborting...");
                return;
            }

            if (!valueUpdateQueue[currentQueue].ContainsKey(args.Tag))
            {
                valueUpdateQueue[currentQueue].Add(args.Tag, () => maid.UpdateField(args.Tag, args.ID, args.Value));
            }
            else
            {
                Debugger.WriteLine(LogLevel.Warning, $"Tag already in update queue {currentQueue}! Aborting...");
            }
        }
        private void UpdateSkillCell <T>(int col, int row)
        {
            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }

            object val = dataGridView_skill_data[col, row].Value;

            if (val is bool)
            {
                val = !(bool)val;
            }

            int skillID = rowToSkillID[row];

            if (!updateSkillTable)
            {
                if (val is T || (col == SKILL_COLUMN_PLAY_COUNT && val is uint))
                {
                    maid.SetSkillValue(skillID, col, val);
                }
                else
                {
                    maid.UpdateSkillData(skillID);
                }
            }
            updateSkillTable = false;
        }
Пример #7
0
        private void UnlockAllMaidClasses(object sender, EventArgs e)
        {
            MaidInfo maid = SelectedMaid;

            for (int i = 0; i < EnumHelper.MaxMaidClass; i++)
            {
                maid.SetMaidClassValue(i, TABLE_COLUMN_HAS, true);
            }
        }
Пример #8
0
        private void UnlockAllYotogiClasses(object sender, EventArgs e)
        {
            MaidInfo maid = SelectedMaid;

            foreach (int yotogiClass in EnumHelper.EnabledYotogiClasses)
            {
                maid.SetYotogiClassValue(yotogiClass, TABLE_COLUMN_HAS, true);
            }
        }
Пример #9
0
        private void UnlockAllSkills(object sender, EventArgs e)
        {
            MaidInfo maid = SelectedMaid;

            foreach (var dataDic in Yotogi.skill_data_list.SelectMany(s => s))
            {
                maid.Maid.Param.SetNewGetSkill(dataDic.Value.id);
                maid.UpdateHasSkill(dataDic.Value.id);
            }
        }
Пример #10
0
        private void SetMaxWorkPlayCount(object sender, EventArgs e)
        {
            MaidInfo maid = SelectedMaid;

            foreach (var noonWork in ScheduleCSVData.NoonWorkData)
            {
                maid.Maid.Param.SetNewGetWork(noonWork.Value.id);
                maid.SetWorkValue(noonWork.Value.id, TABLE_COLUMN_TOTAL_XP, 999U);
            }
        }
Пример #11
0
 private void SetMaxYotogiLevel(object sender, EventArgs e)
 {
     Debugger.Assert(() =>
     {
         MaidInfo maid = SelectedMaid;
         foreach (var dataDic in Yotogi.skill_data_list.SelectMany(s => s))
         {
             maid.Maid.Param.SetNewGetSkill(dataDic.Value.id);
             maid.Maid.Param.AddSkillExp(dataDic.Value.id, 10000);
             maid.Maid.Param.status_.skill_data[dataDic.Value.id].play_count = 1;
             maid.UpdateSkillData(dataDic.Value.id);
         }
     }, "Failed to set all yotogi levels to max");
 }
Пример #12
0
 private void UpdateGameValue(Control c, object value)
 {
     if (uiControls.ContainsKey(c))
     {
         MaidInfo maid = SelectedMaid;
         if (maid == null)
         {
             return;
         }
         Debugger.Assert(
             () =>
         {
             MaidChangeType type = uiControls[c];
             if (type == MaidChangeType.YotogiClassType)
             {
                 value = EnumHelper.EnabledYotogiClasses[(int)value];
             }
             Debugger.WriteLine(
                 LogLevel.Info,
                 $"Attempting to update value {type} to {value}. Allowed: {!valueUpdate[type]}.");
             if (!valueUpdate[type])
             {
                 maid.SetValue(type, value);
             }
             valueUpdate[type] = false;
         },
             $"Failed to set maid value for {maid.Maid.Param.status.first_name} {maid.Maid.Param.status.last_name}");
     }
     else if (uiControlsPlayer.ContainsKey(c))
     {
         if (Player == null)
         {
             return;
         }
         Debugger.Assert(
             () =>
         {
             PlayerChangeType type = uiControlsPlayer[c];
             Debugger.WriteLine(
                 LogLevel.Info,
                 $"Attempting to update player value {type} to {value}. Allowed: {!valueUpdatePlayer[type]}.");
             if (!valueUpdatePlayer[type])
             {
                 Player.SetValue(type, value);
             }
             valueUpdatePlayer[type] = false;
         },
             "Failed to set player value");
     }
 }
        private void OnCellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (clearingTables)
            {
                return;
            }
            if (e.ColumnIndex != PARAMS_COLUMN_LOCK)
            {
                return;
            }
            DataGridView table = (DataGridView)sender;

            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }

            MaidChangeType?type = null;

            if (table == dataGridView_params)
            {
                type = maidParamsTableDic[e.RowIndex];
            }
            else if (table == dataGridView_ero_zones)
            {
                type = maidEroTableDic[e.RowIndex];
            }
            else if (table == dataGridView_statistics)
            {
                type = maidStatsTableDic[e.RowIndex];
            }
            if (type == null)
            {
                return;
            }

            bool val = !((bool)table[e.ColumnIndex, e.RowIndex].Value);

            if (val)
            {
                maid.Lock(type.Value);
            }
            else
            {
                maid.Unlock(type.Value);
            }
        }
        private void OnNightWorkCellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (clearingTables || e.ColumnIndex != TABLE_COLUMN_HAS)
            {
                return;
            }

            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }
            UpdateNightWorkCell(e.ColumnIndex, e.RowIndex);
        }
        private void UpdateMaid_YotogiClassValue <T>(DataGridView table, int col, int row)
        {
            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }

            object val = table[col, row].Value;

            if (val is bool)
            {
                val = !((bool)val);
            }

            if (table == dataGridView_maid_classes)
            {
                if (!updateMaidClassField)
                {
                    if (val is T)
                    {
                        maid.SetMaidClassValue(row, col, val);
                    }
                    else
                    {
                        maid.UpdateField(MaidChangeType.MaidClassType, row);
                    }
                }
                updateMaidClassField = false;
            }
            else if (table == dataGridView_yotogi_classes)
            {
                if (!updateYotogiClassField)
                {
                    if (val is T)
                    {
                        maid.SetYotogiClassValue(EnumHelper.EnabledYotogiClasses[row], col, val);
                    }
                    else
                    {
                        maid.UpdateField(MaidChangeType.YotogiClassType, EnumHelper.EnabledYotogiClasses[row]);
                    }
                }
                updateYotogiClassField = false;
            }
        }
Пример #16
0
        private void SetForceDisableAll(object sender, EventArgs e)
        {
            MaidInfo maid = SelectedMaid;

            Debugger.Assert(() =>
            {
                foreach (var noonWork in ScheduleCSVData.NoonWorkData)
                {
                    maid.SetWorkValue(noonWork.Value.id, TABLE_COLUMN_HAS, false);
                }
                foreach (var nightWork in ScheduleCSVData.NightWorkData)
                {
                    maid.SetNightWorkValue(nightWork.Value.id, false);
                    maid.UpdateNightWorkValue(nightWork.Value.id);
                }
            }, "Failed to force all work disabled");
        }
Пример #17
0
        private void DrawListBox(object sender, DrawItemEventArgs e)
        {
            e.DrawBackground();
            if (listBox1.Items.Count == 0)
            {
                return;
            }
            MaidInfo m = listBox1.Items[e.Index] as MaidInfo;

            if (m == null)
            {
                return;
            }

            Image maidThumb;

            maidThumbnails.TryGetValue(m.Maid.Param.status.guid, out maidThumb);

            if (maidThumb == null && Resources.DefaultThumbnail == null)
            {
                e.Graphics.FillRectangle(Brushes.BlueViolet, e.Bounds.X, e.Bounds.Y, e.Bounds.Height, e.Bounds.Height);
            }
            else
            {
                e.Graphics.DrawImage(
                    maidThumb ?? Resources.DefaultThumbnail,
                    e.Bounds.X,
                    e.Bounds.Y,
                    e.Bounds.Height,
                    e.Bounds.Height);
            }
            string name = Plugin.UseJapaneseNameStyle
                          ? $"{m.Maid.Param.status.last_name} {m.Maid.Param.status.first_name}"
                          : $"{m.Maid.Param.status.first_name} {m.Maid.Param.status.last_name}";

            e.Graphics.DrawString(
                name,
                e.Font,
                Brushes.Black,
                e.Bounds.X + e.Bounds.Height + 5,
                e.Bounds.Y + (e.Bounds.Height - e.Font.Height) / 2,
                StringFormat.GenericDefault);

            e.DrawFocusRectangle();
        }
        private void OnClassUpdated(object sender, HookEventArgs args)
        {
            Debugger.WriteLine("Updating maid and/or yotogi class info.");
            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                Debugger.WriteLine(LogLevel.Warning, "Maid is NULL!");
                return;
            }

            if (maid.Maid != args.CallerMaid)
            {
                Debugger.WriteLine(LogLevel.Warning, "Caller maid is not the selected one! Aborting...");
                return;
            }

            if (valueUpdateQueue[currentQueue].ContainsKey(args.Tag))
            {
                Debugger.WriteLine(LogLevel.Error, "Tag already in update queue! Aborting...");
                return;
            }
            switch (args.Tag)
            {
            case MaidChangeType.MaidClassType:
                valueUpdateQueue[currentQueue].Add(args.Tag, () => maid.UpdateMaidClasses());
                break;

            case MaidChangeType.YotogiClassType:
                valueUpdateQueue[currentQueue].Add(args.Tag, () => maid.UpdateYotogiClasses());
                break;

            case MaidChangeType.MaidAndYotogiClass:
                valueUpdateQueue[currentQueue].Add(
                    args.Tag,
                    () =>
                {
                    maid.UpdateMaidBonusValues();
                    maid.UpdateMaidClasses();
                    maid.UpdateYotogiClasses();
                });
                break;
            }
        }
Пример #19
0
        private void SetMaxClassLevel(object sender, EventArgs e)
        {
            MaidInfo selected = SelectedMaid;
            Maid     maid     = selected.Maid;

            for (int maidClass = 0; maidClass < EnumHelper.MaxMaidClass; maidClass++)
            {
                SetClassIsHave(maid, "maid_class_data", maidClass, true);
                SetClassLevel(maid, "maid_class_data", maidClass, 10);
            }
            selected.UpdateMaidClasses();

            foreach (int yotogiClass in EnumHelper.EnabledYotogiClasses)
            {
                SetClassIsHave(maid, "yotogi_class_data", yotogiClass, true);
                SetClassLevel(maid, "yotogi_class_data", yotogiClass, 10);
            }
            selected.UpdateYotogiClasses();
        }
Пример #20
0
        private void SetClassLevel(object sender, EventArgs e)
        {
            Debugger.WriteLine(LogLevel.Info, "Prompting class level set.");
            uint       v;
            TextDialog td = new TextDialog(Translation.GetTranslation("GUI_CLASS_LVL_TITLE"),
                                           Translation.GetTranslation("GUI_CLASS_LVL_PROMPT"), "0",
                                           s => uint.TryParse(s, out v) && (v <= 10), Translation.GetTranslation("OK"),
                                           Translation.GetTranslation("CANCEL"))
            {
                StartPosition = FormStartPosition.CenterParent
            };
            DialogResult dr = td.ShowDialog(this);

            Debugger.WriteLine(LogLevel.Info, $"Prompt result: {EnumHelper.GetName(dr)}, {td.Input}");

            if (dr != DialogResult.OK)
            {
                return;
            }
            v = uint.Parse(td.Input);
            int val = (int)v;

            td.Dispose();

            MaidInfo selected = SelectedMaid;
            Maid     maid     = selected.Maid;

            for (int maidClass = 0; maidClass < EnumHelper.MaxMaidClass; maidClass++)
            {
                SetClassIsHave(maid, "maid_class_data", maidClass, true);
                SetClassLevel(maid, "maid_class_data", maidClass, val);
            }
            selected.UpdateMaidClasses();

            foreach (int yotogiClass in EnumHelper.EnabledYotogiClasses)
            {
                SetClassIsHave(maid, "yotogi_class_data", yotogiClass, true);
                SetClassLevel(maid, "yotogi_class_data", yotogiClass, val);
            }

            selected.UpdateYotogiClasses();
        }
        private void OnStatusUpdated(object sender, StatusUpdateEventArgs args)
        {
            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }

            if (args.CallerMaid != maid.Maid)
            {
                return;
            }

            Debugger.WriteLine(
                LogLevel.Info,
                $"Updating {EnumHelper.GetName(args.Tag)}.{(args.Tag == MaidChangeType.Feature ? Translation.GetTranslation(EnumHelper.GetName((Feature) args.EnumVal)) : Translation.GetTranslation(EnumHelper.GetName((Propensity) args.EnumVal)))} to {args.Value}...");

            maid.UpdateMiscStatus(args.Tag, args.EnumVal, args.Value);
        }
        private void OnNightWorkCellChanged(object sender, DataGridViewCellEventArgs e)
        {
            if (clearingTables || e.ColumnIndex != TABLE_COLUMN_HAS)
            {
                return;
            }
            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }

            int workID = rowToNightWorkID[e.RowIndex];

            if (!updateNightWorkTable)
            {
                maid.UpdateNightWorkValue(workID);
            }
            updateNightWorkTable = false;
        }
        private void OnPropensityChecked(object sender, ItemCheckEventArgs e)
        {
            if (clearingTables)
            {
                return;
            }

            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }

            if (!updatePropensity)
            {
                maid.Maid.Param.SetPropensity((Propensity)(e.Index + 1), e.NewValue == CheckState.Checked);
                maid.UpdateMiscStatus(MaidChangeType.Propensity, e.Index + 1);
            }
            updatePropensity = false;
        }
        private void OnFeatureChecked(object sender, ItemCheckEventArgs e)
        {
            if (clearingTables)
            {
                return;
            }

            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }

            if (!updateFeature)
            {
                maid.Maid.Param.SetFeature((Feature)(e.Index + 1), e.NewValue == CheckState.Checked);
                maid.UpdateMiscStatus(MaidChangeType.Feature, e.Index + 1);
            }
            updateFeature = false;
        }
        private void OnStatusChanged(object sender, StatusEventArgs args)
        {
            Debugger.WriteLine($"Changed status for property {EnumHelper.GetName(args.Tag)}");
            Debugger.WriteLine(
                $"Called maid: {args.CallerMaid.Param.status.first_name} {args.CallerMaid.Param.status.last_name}");

            if (!IsMaidLoaded(args.CallerMaid))
            {
                Debugger.WriteLine(LogLevel.Error, "Maid not in the list! Aborting!");
                return;
            }

            MaidInfo maid = GetMaidInfo(args.CallerMaid);

            if (maid.IsLocked(args.Tag))
            {
                Debugger.WriteLine(LogLevel.Info, "Value locked! Aborting changes...");
                args.BlockAssignment = true;
                return;
            }

            if (SelectedMaid != null && SelectedMaid.Maid != maid.Maid)
            {
                Debugger.WriteLine(LogLevel.Warning, "Selected maids are different!");
                return;
            }

            if (!valueUpdateQueue[currentQueue].ContainsKey(args.Tag))
            {
                Debugger.WriteLine(LogLevel.Info, "Adding to update queue");
                valueUpdateQueue[currentQueue].Add(args.Tag, () => maid.UpdateField(args.Tag));
            }
            else
            {
                Debugger.WriteLine(
                    LogLevel.Warning,
                    $"Already in update queue {currentQueue}! Queue length: {valueUpdateQueue[currentQueue].Count}");
            }
        }
Пример #26
0
        private void OnSelectedValueChanged(object sender, EventArgs e)
        {
            Debugger.WriteLine("Changed selected maid!");
            currentQueue = -1;
            valueUpdateQueue[0].Clear();
            valueUpdateQueue[1].Clear();
            currentQueue = 0;
            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                Debugger.WriteLine(LogLevel.Error, "MAID IS NULL");
                ClearAllFields();
                ControlsEnabled = false;
                return;
            }
            Debugger.WriteLine(
                LogLevel.Info,
                $"New maid: {maid.Maid.Param.status.first_name} {maid.Maid.Param.status.last_name}");
            ControlsEnabled = true;
            maid.UpdateAll();
        }
        private void UpdateNightWorkCell(int col, int row)
        {
            if (col != TABLE_COLUMN_HAS)
            {
                return;
            }
            MaidInfo maid = SelectedMaid;

            if (maid == null)
            {
                return;
            }

            bool val    = !(bool)dataGridView_night_work[col, row].Value;
            int  workID = rowToNightWorkID[row];

            if (!updateNightWorkTable)
            {
                maid.SetNightWorkValue(workID, val);
            }
            updateNightWorkTable = false;
        }
Пример #28
0
        private void UnlockAllValues(object sender, EventArgs e)
        {
            MaidInfo maid = SelectedMaid;

            maid.SetAllLock(false);
        }
Пример #29
0
        private void SetUnlockMaxAllMaids(object sender, EventArgs e)
        {
            foreach (var maid in loadedMaids)
            {
                MaidInfo  maidInfo    = maid.Value;
                Maid      currentMaid = maid.Key;
                MaidParam maidParam   = currentMaid.Param;
                Debugger.WriteLine(LogLevel.Info,
                                   $"Setting all to max for {currentMaid.Param.status.first_name} {currentMaid.Param.status.last_name}");

                for (int maidClass = 0; maidClass < EnumHelper.MaxMaidClass; maidClass++)
                {
                    SetClassIsHave(currentMaid, "maid_class_data", maidClass, true);
                    SetClassLevel(currentMaid, "maid_class_data", maidClass, 10);
                }
                maidInfo.UpdateMaidClasses();

                foreach (int yotogiClass in EnumHelper.EnabledYotogiClasses)
                {
                    SetClassIsHave(currentMaid, "yotogi_class_data", yotogiClass, true);
                    SetClassLevel(currentMaid, "yotogi_class_data", yotogiClass, 10);
                }
                maidInfo.UpdateYotogiClasses();

                maidParam.SetSexualMouth(1000);
                maidParam.SetSexualCuri(1000);
                maidParam.SetSexualNipple(1000);
                maidParam.SetSexualThroat(1000);

                for (Feature i = Feature.Null + 1; i < EnumHelper.MaxFeature; i++)
                {
                    maidParam.SetFeature(i, true);
                }

                for (Propensity i = Propensity.Null + 1; i < EnumHelper.MaxPropensity; i++)
                {
                    maidParam.SetPropensity(i, true);
                }

                maidParam.SetCare(9999);
                maidParam.SetCharm(9999);
                maidParam.SetElegance(9999);
                maidParam.SetEvaluation(999999L);
                maidParam.SetFrustration(0);
                maidParam.SetHentai(9999);
                maidParam.SetHousi(9999);
                maidParam.SetHp(999);
                maidParam.SetInyoku(9999);
                maidParam.SetLikability(999);
                maidParam.SetLovely(9999);
                maidParam.SetMValue(9999);
                maidParam.SetMaidPoint(999);
                maidParam.SetPlayNumber(9999);
                maidParam.SetMind(9999);
                maidParam.SetReason(9999);
                maidParam.SetReception(9999);
                maidParam.SetPopularRank(99);
                maidParam.SetSales(9999999999L);
                maidParam.SetCurHp(999);
                maidParam.SetCurMind(999);
                maidParam.SetCurReason(999);

                foreach (var noonWork in ScheduleCSVData.NoonWorkData)
                {
                    maidParam.SetNewGetWork(noonWork.Value.id);
                    maidInfo.SetWorkValue(noonWork.Value.id, TABLE_COLUMN_TOTAL_XP, 999U);
                }

                foreach (var dataDic in Yotogi.skill_data_list.SelectMany(s => s))
                {
                    maidParam.SetNewGetSkill(dataDic.Value.id);
                    maidParam.AddSkillExp(dataDic.Value.id, 10000);
                    maidParam.status_.skill_data[dataDic.Value.id].play_count = 1;
                    maidInfo.UpdateSkillData(dataDic.Value.id);
                }

                foreach (var dataDic in Yotogi.skill_data_list.SelectMany(s => s))
                {
                    maidParam.SetNewGetSkill(dataDic.Value.id);
                    maidInfo.UpdateHasSkill(dataDic.Value.id);
                }
            }
        }
        private void UpdateMaids(List <Maid> newMaids)
        {
            Debugger.Assert(
                () =>
            {
                if (newMaids.Count != loadedMaids.Count)
                {
                    goto update;
                }

                newMaids.Sort((m1, m2) => comparer.Compare(m1, m2));
                if (newMaids.SequenceEqual(loadedMaids.Values.Select(m => m.Maid), comparer))
                {
                    return;
                }

                update:
#if DEBUG
                Stopwatch sw = Stopwatch.StartNew();
#endif
                Debugger.WriteLine(LogLevel.Info, "Updating maid list!");
                Debugger.WriteLine(LogLevel.Info, $" New count:  {newMaids.Count}, Loaded count: {loadedMaids.Count}");
                loadedMaids = new SortedList <Maid, MaidInfo>(
                    loadedMaids.Where(
                        m =>
                {
                    bool result = newMaids.Contains(m.Key);
                    if (result)
                    {
                        newMaids.Remove(m.Key);
                    }
                    else
                    {
                        if (SelectedMaid != null && m.Value.Maid == SelectedMaid.Maid)
                        {
                            currentQueue = 0;
                            valueUpdateQueue[0].Clear();
                            valueUpdateQueue[1].Clear();
                        }
                        if (maidThumbnails.ContainsKey(m.Key.Param.status.guid))
                        {
                            maidThumbnails[m.Key.Param.status.guid].Dispose();
                        }
                        maidThumbnails.Remove(m.Key.Param.status.guid);
                    }
                    return(result);
                }).ToList().Union(
                        newMaids.Select(
                            m =>
                {
                    Debugger.WriteLine(LogLevel.Info, "Adding new maid info.");
                    MaidInfo info = new MaidInfo(m, this);
                    Debugger.WriteLine(LogLevel.Info, "Loading thumbnail");
                    Texture2D thumb = m.GetThumIcon();
                    if (thumb == null)
                    {
                        return(new KeyValuePair <Maid, MaidInfo>(m, info));
                    }
                    using (MemoryStream stream = new MemoryStream(thumb.EncodeToPNG()))
                    {
                        Debugger.WriteLine("Loading PNG of size: " + stream.Length);
                        maidThumbnails.Add(m.Param.status.guid, Image.FromStream(stream));
                    }
                    return(new KeyValuePair <Maid, MaidInfo>(m, info));
                })).ToDictionary(m => m.Key, m => m.Value),
                    comparer);


                Debugger.WriteLine(LogLevel.Info, $"New loaded maids count: {loadedMaids.Count}");
#if DEBUG
                sw.Stop();
                Debugger.WriteLine(LogLevel.Info, $"Updated maid list in {sw.Elapsed.TotalMilliseconds} ms");

                newMaids.ForEach(
                    m => Debugger.WriteLine($"Added {m.Param.status.first_name} {m.Param.status.last_name}"));
                Debugger.WriteLine();
#endif
                Debugger.WriteLine("Updating list.");
                UpdateList();
                Debugger.WriteLine("Finished updating list.");
            },
                "Failed to update maid list");
        }