private static bool Matches(BossFight bossFight, HashSet <Boss> startingBosses, Music music, Map map, MapTileCoordinate mapTile)
 {
     if (bossFight.startingBosses != null && !bossFight.startingBosses.SetEquals(startingBosses))
     {
         return(false);
     }
     if (bossFight.extraCondition == null)
     {
         return(true);
     }
     return(bossFight.extraCondition(startingBosses, music, map, mapTile));
 }
Example #2
0
        private void ReadMemory()
        {
            practiceModeContext.ResetSendTriggers();

            var processlist = Process.GetProcessesByName("rabiribi");

            if (processlist.Length > 0)
            {
                Process process      = processlist[0];
                var     memoryHelper = new MemoryHelper(process);

                if (process.MainWindowTitle != mainContext.oldtitle)
                {
                    var    result = titleReg.Match(process.MainWindowTitle);
                    string rabiver;
                    if (result.Success)
                    {
                        rabiver            = result.Groups[1].Value;
                        mainContext.veridx = Array.IndexOf(StaticData.VerNames, rabiver);
                        if (mainContext.veridx < 0)
                        {
                            mainContext.GameVer = rabiver + " Running (not supported)";

                            return;
                        }
                    }
                    else
                    {
                        mainContext.veridx  = -1;
                        mainContext.GameVer = "Running (Unknown version)";

                        return;
                    }
                    mainContext.GameVer  = rabiver + " Running";
                    mainContext.oldtitle = process.MainWindowTitle;
                }


                if (mainContext.veridx < 0)
                {
                    return;
                }


                #region read igt

                int igt = memoryHelper.GetMemoryValue <int>(StaticData.IGTAddr[mainContext.veridx]);
                if (igt > 0 && mainContext.Igt)
                {
                    sendigt((float)igt / 60);
                }

                #endregion

                #region Detect Reload

                bool reloaded = false;
                {
                    // When reloading, the frame numbers look like this:
                    // Case 1: (PLAYTIME frame steps down briefly before going to 0)
                    //         1108, 1109, 1110, 1110, 1110, 540, 0, 0, 0, 0, 0, 540, 540, 541, 542, 544,
                    // Case 2: (PLAYTIME frame goes straight to 0)
                    //         1108, 1109, 1110, 1110, 1110, 0, 0, 0, 0, 0, 540, 540, 541, 542, 544,
                    // This can sometimes cause reloads to be detected twice (which is usually not a problem though, but ocd lol)
                    // So we use a switch to "prime" the canReload flag whenever it detects the PLAYTIME increasing.
                    // the canReload flag is unset when a reload is detected, and remains unset until PLAYTIME starts increasing again.

                    int playtime = memoryHelper.GetMemoryValue <int>(StaticData.PlaytimeAddr[mainContext.veridx]);
                    reloaded = playtime < mainContext.lastplaytime;

                    if (playtime > mainContext.lastplaytime)
                    {
                        mainContext.canReload = true;
                    }
                    if (mainContext.canReload && playtime < mainContext.lastplaytime)
                    {
                        PracticeModeSendTrigger(SplitTrigger.Reload);
                        DebugLog($"Reload Game! {playtime}/{mainContext.lastplaytime}");
                        mainContext.canReload = false;
                    }
                    mainContext.lastplaytime = playtime;
                }

                #endregion


                #region CheckMoney

                if (mainContext.Computer)
                {
                    var newmoney = memoryHelper.GetMemoryValue <int>(StaticData.MoneyAddress[mainContext.veridx]);
                    if (newmoney - mainContext.lastmoney == 17500)
                    {
                        SpeedrunSendSplit();
                        DebugLog("get 17500 en, split");
                    }
                    mainContext.lastmoney = newmoney;
                }

                #endregion

                int mapid = memoryHelper.GetMemoryValue <int>(StaticData.MapAddress[mainContext.veridx]);
                if (mainContext.lastmapid != mapid)
                {
                    PracticeModeMapChangeTrigger(mainContext.lastmapid, mapid);
                    DebugLog("newmap: " + mapid + ":" + StaticData.GetMapName(mapid));
                    mainContext.GameMap   = StaticData.GetMapName(mapid);
                    mainContext.lastmapid = mapid;
                }

                #region MapTile
                {
                    int   entityArrayPtr = memoryHelper.GetMemoryValue <int>(StaticData.EnemyPtrAddr[mainContext.veridx]);
                    float px             = memoryHelper.GetMemoryValue <float>(entityArrayPtr + StaticData.EnemyEntityXPositionOffset[mainContext.veridx], false);
                    float py             = memoryHelper.GetMemoryValue <float>(entityArrayPtr + StaticData.EnemyEntityYPositionOffset[mainContext.veridx], false);
                    var   mapTile        = MapTileCoordinate.FromWorldPosition(mapid, px, py);
                    if (!mapTile.Equals(mainContext.lastMapTile))
                    {
                        PracticeModeMapTileChangeTrigger(mainContext.lastMapTile, mapTile);
                        //DebugLog($"Map Tile: ({mapTile.x}, {mapTile.y})");
                        mainContext.GameMapTile = $"({mapTile.x}, {mapTile.y})";
                        mainContext.lastMapTile = mapTile;
                    }
                }
                #endregion


                #region checkTM



                #endregion

                #region Music

                int musicaddr = StaticData.MusicAddr[mainContext.veridx];
                int musicid   = memoryHelper.GetMemoryValue <int>(musicaddr);

                #region Detect Start Game

                if (musicid == 53)
                {
                    int blackness = memoryHelper.GetMemoryValue <int>(StaticData.BlacknessAddr[mainContext.veridx]);
                    if (mainContext.previousBlackness == 0 && blackness >= 100000)
                    {
                        // Sudden increase by 100000
                        // Have to be careful, though. I don't know whether anything else causes blackness to increase by 100000
                        if (mainContext.AutoStart)
                        {
                            SpeedrunSendStartTimer();
                        }
                        DebugLog("Start Game!");
                        mainContext.LastBossEnd = DateTime.Now;
                    }
                    mainContext.previousBlackness = blackness;
                }

                #endregion


                if (musicid > 0)
                {
                    if (mainContext.lastmusicid != musicid)
                    {
                        PracticeModeMusicChangeTrigger(mainContext.lastmusicid, musicid);
                        DebugLog("new music:" + musicid + ":" + StaticData.GetMusicName(musicid));
                        mainContext.GameMusic = StaticData.GetMusicName(musicid);

                        if ((musicid == 45 || musicid == 46 || musicid == 53) && mainContext.AutoReset)
                        {
                            DebugLog("Title music, reset");
                            //reset
                            SpeedrunSendReset();
                            mainContext.Alius1        = true;
                            mainContext.Noah1Reload   = false;
                            mainContext.Bossbattle    = false;
                            mainContext.LastBossEnd   = null;
                            mainContext.LastBossStart = null;
                        }

                        else
                        {
                            var bossmusicflag = StaticData.IsBossMusic(musicid);
                            if (bossmusicflag)
                            {
                                if (mainContext.Bossbattle)
                                {
                                    if (mainContext.Noah1Reload && (mainContext.lastmusicid == 52 || musicid == 52))
                                    {
                                        DebugLog("noah 1 reload? ignore");
                                    }
                                    else
                                    {
                                        if (mainContext.MusicStart || mainContext.MusicEnd)
                                        {
                                            SpeedrunSendSplit();
                                            DebugLog("new boss music, split");
                                        }
                                        if (musicid == 37)
                                        {
                                            mainContext.Noah1Reload = true;
                                            DebugLog("noah1 music start, ignore MR forever");
                                        }
                                    }

                                    mainContext.lastmusicid = musicid;
                                    return;
                                }
                            }
                            if (!mainContext.Bossbattle)
                            {
                                if (musicid == 54 && mainContext.Alius1 && !mainContext.ForceAlius1)
                                {
                                    mainContext.Bossbattle = false;
                                    mainContext.Alius1     = false;
                                    DebugLog("Alius music, ignore once");
                                }
                                else if (musicid == 42 && mapid == 1 && mainContext.Irisu1)
                                {
                                    mainContext.Bossbattle = false;
                                    DebugLog("Irisu P1, ignore");
                                }
                                else
                                {
                                    if (bossmusicflag)
                                    {
                                        if (mapid == 5 && musicid == 44 && mainContext.SideCh)
                                        {
                                            mainContext.Bossbattle = false;
                                            DebugLog("sidechapter, ignore");
                                        }
                                        else
                                        {
                                            PracticeModeSendTrigger(SplitTrigger.BossStart);
                                            mainContext.Bossbattle   = true;
                                            mainContext.lastbosslist = new List <int>();
                                            mainContext.lastnoah3hp  = -1;
                                            if (musicid == 37)
                                            {
                                                mainContext.Noah1Reload = true;
                                                DebugLog("noah1 music start, ignore MR forever");
                                            }
                                            if (mainContext.MusicStart)
                                            {
                                                SpeedrunSendSplit();
                                                DebugLog("music start, split");
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                if (!bossmusicflag) //boss music end!
                                {
                                    mainContext.Bossbattle = false;
                                    if (mainContext.MusicEnd)
                                    {
                                        if (!mainContext.DontSplitOnReload || !reloaded)
                                        {
                                            SpeedrunSendSplit();
                                        }
                                        if (!reloaded)
                                        {
                                            PracticeModeSendTrigger(SplitTrigger.BossEnd);
                                        }
                                        DebugLog(reloaded ? "music end, don't split (reload)" : "music end, split");
                                    }
                                }
                            }
                        }
                        mainContext.lastmusicid = musicid;
                    }
                }
                else
                {
                    mainContext.GameMusic = "N/A";
                }

                #endregion Music

                #region SpecialBOSS

                if (mainContext.Bossbattle)
                {
                    if (mainContext.MiruDe || false)//todo noah3 option
                    {
                        int Noah3HP = -1;

                        if (StaticData.IsValidMap(mapid))
                        {
                            int        ptr    = memoryHelper.GetMemoryValue <int>(StaticData.EnemyPtrAddr[mainContext.veridx]);
                            List <int> bosses = new List <int>();
                            for (var i = 0; i < 50; i++)
                            {
                                ptr = ptr + StaticData.EnemyEntitySize[mainContext.veridx];

                                var emyid = memoryHelper.GetMemoryValue <int>(ptr + StaticData.EnemyEntityIDOffset[mainContext.veridx], false);
                                if (StaticData.IsBoss(emyid))
                                {
                                    bosses.Add(emyid);
                                    if (emyid == 1053)
                                    {
                                        Noah3HP = memoryHelper.GetMemoryValue <int>(ptr + StaticData.EnemyEntityHPOffset[mainContext.veridx], false);
                                    }
                                }
                            }
                            if (mainContext.MiruDe && mapid == 8)
                            {
                                foreach (var boss in mainContext.lastbosslist)
                                {
                                    if (boss == 1043)
                                    {
                                        if (!bosses.Contains(boss)) //despawn
                                        {
                                            SpeedrunSendSplit();
                                            DebugLog("miru despawn, split");
                                            mainContext.Bossbattle = false;
                                        }
                                    }
                                }
                            }

//                            if (cbBoss3.Checked)
//                            {
//                                if (bosses.Contains(1053) && Noah3HP < lastnoah3hp && Noah3HP == 1)
//                                {
//                                    sendsplit();
//                                    DebugLog("noah3 hp 1, split");
//                                    bossbattle = false;
//                                }
//                            }
                            if (mainContext.Tm2 && musicid == 8)
                            {
                                bool f = true;
                                foreach (var boss in mainContext.lastbosslist)
                                {
                                    if (boss == 1024)
                                    {
                                        if (!bosses.Contains(boss)) //despawn
                                        {
                                            SpeedrunSendSplit();
                                            DebugLog("nixie despawn, split");
                                            mainContext.Bossbattle = false;
                                            f = false;
                                            break;
                                        }
                                    }
                                }

                                int newTM = memoryHelper.GetMemoryValue <int>(StaticData.TownMemberAddr[mainContext.veridx]);
                                if (newTM - mainContext.lastTM == 1 && f) //for after 1.71 , 1.71 isn't TM+2 at once when skip Nixie, it's TM+1 twice

                                {
                                    if (DateTime.Now - mainContext.LastTMAddTime < TimeSpan.FromSeconds(1))
                                    {
                                        var d = DateTime.Now - mainContext.LastTMAddTime;
                                        mainContext.Bossbattle = false;
                                        SpeedrunSendSplit();
                                        DebugLog("TM+2 in " + d.TotalMilliseconds + " ms, split");
                                    }
                                    mainContext.LastTMAddTime = DateTime.Now;
                                }
                                else if (newTM - mainContext.lastTM == 2 && f)//for 1.65-1.70
                                {
                                    mainContext.Bossbattle = false;
                                    SpeedrunSendSplit();
                                    DebugLog("TM+2, split");
                                }
                                mainContext.lastTM = newTM;
                            }
                            mainContext.lastbosslist = bosses;
                            mainContext.lastnoah3hp  = Noah3HP;
                        }
                    }
                }


                #endregion SpecialBOSS

                if (mainContext.DebugArea)
                {
                    int ptr = memoryHelper.GetMemoryValue <int>(StaticData.EnemyPtrAddr[mainContext.veridx]);
                    //                    List<int> bosses = new List<int>();
                    //                    List<int> HPS = new List<int>();
//                    this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => debugContext.BossList.Clear()));
//                    ptr += StaticData.EnemyEntitySize[mainContext.veridx] * 3;
                    for (var i = 0; i < 50; i++)
                    {
                        ptr += StaticData.EnemyEntitySize[mainContext.veridx];
                        debugContext.BossList[i].BossID = memoryHelper.GetMemoryValue <int>(ptr + StaticData.EnemyEntityIDOffset[mainContext.veridx], false);
                        debugContext.BossList[i].BossHP = memoryHelper.GetMemoryValue <int>(ptr + StaticData.EnemyEntityHPOffset[mainContext.veridx], false);
                    }
                }
                debugContext.BossEvent = mainContext.Bossbattle;
            }
            else
            {
                mainContext.oldtitle = "";

                mainContext.GameVer   = "Not Found";
                mainContext.GameMusic = "N/A";
            }
            mainContext.NotifyTimer();
            SendPracticeModeMessages();
        }
        public MemorySnapshot(MemoryHelper memoryHelper, int veridx)
        {
            t_playtime = memoryHelper.GetMemoryValue <int>(StaticData.IGTAddr[veridx]);
            playtime   = memoryHelper.GetMemoryValue <int>(StaticData.PlaytimeAddr[veridx]);
            blackness  = memoryHelper.GetMemoryValue <int>(StaticData.BlacknessAddr[veridx]);

            mapid   = memoryHelper.GetMemoryValue <int>(StaticData.MapAddress[veridx]);
            musicid = memoryHelper.GetMemoryValue <int>(StaticData.MusicAddr[veridx]);
            money   = memoryHelper.GetMemoryValue <int>(StaticData.MoneyAddress[veridx]);

            carrotXp    = memoryHelper.GetMemoryValue <int>(0xD654BC);
            hammerXp    = memoryHelper.GetMemoryValue <int>(0xD654B4);
            ribbonXp    = memoryHelper.GetMemoryValue <int>(0xD654B8);
            itemPercent = memoryHelper.GetMemoryValue <float>(0xA730E8);
            nextHammer  = StaticData.GetNextHammerLevel(hammerXp);
            nextRibbon  = StaticData.GetNextRibbonLevel(ribbonXp);
            nextCarrot  = StaticData.GetNextCarrotLevel(carrotXp);

            minimapPosition = memoryHelper.GetMemoryValue <int>(0xA72E08);

            nAttackUps = countItems(memoryHelper, 0xD6352C, 0xD63628);
            nHpUps     = countItems(memoryHelper, 0xD6342C, 0xD63528);
            nManaUps   = countItems(memoryHelper, 0xD6362C, 0xD63728);
            nPackUps   = countItems(memoryHelper, 0xD6382C, 0xD63928);
            nRegenUps  = countItems(memoryHelper, 0xD6372C, 0xD63828);

            entityArrayPtr = memoryHelper.GetMemoryValue <int>(StaticData.EnenyPtrAddr[veridx]);

            hp    = memoryHelper.GetMemoryValue <int>(entityArrayPtr + 0x4D8, false);
            maxhp = memoryHelper.GetMemoryValue <int>(entityArrayPtr + 0x4E8, false);

            currentSprite = memoryHelper.GetMemoryValue <int>(entityArrayPtr + 0x654, false);
            actionFrame   = memoryHelper.GetMemoryValue <int>(entityArrayPtr + 0x660, false);

            amulet  = memoryHelper.GetMemoryValue <float>(entityArrayPtr + 0x52C, false);
            boost   = memoryHelper.GetMemoryValue <int>(entityArrayPtr + 0x5DC, false);
            mana    = memoryHelper.GetMemoryValue <float>(entityArrayPtr + 0x6B8, false);
            stamina = memoryHelper.GetMemoryValue <int>(entityArrayPtr + 0x5B4, false);

            px      = memoryHelper.GetMemoryValue <float>(entityArrayPtr + 0xC, false);
            py      = memoryHelper.GetMemoryValue <float>(entityArrayPtr + 0x10, false);
            mapTile = MapTileCoordinate.FromWorldPosition(mapid, px, py);

            // Read Entity Array and Search for boss data
            bossList        = new List <BossStats>();
            nActiveEntities = 0;
            entityArraySize = 4;
            int entitySize   = StaticData.EnenyEntitySize[veridx];
            int currArrayPtr = entityArrayPtr + entitySize * 4;

            for (int i = 0; i < 500; ++i)
            {
                // (Hard limit of reading 500 entries)
                int entityId = memoryHelper.GetMemoryValue <int>(
                    currArrayPtr + StaticData.EnenyEnitiyIDOffset[veridx], false);
                int entityMaxHp = memoryHelper.GetMemoryValue <int>(
                    currArrayPtr + StaticData.EnenyEnitiyMaxHPOffset[veridx], false);

                if (entityId == 0 && entityMaxHp == 0)
                {
                    break;
                }

                int activeFlag = memoryHelper.GetMemoryValue <int>(
                    currArrayPtr + StaticData.EnenyEnitiyIsActiveOffset[veridx], false);
                int animationState = memoryHelper.GetMemoryValue <int>(
                    currArrayPtr + StaticData.EnenyEnitiyAnimationOffset[veridx], false);

                bool isAlive = activeFlag == 1 && animationState >= 0;

                if (isAlive && StaticData.IsBoss(entityId))
                {
                    BossStats boss;
                    boss.entityArrayIndex = entityArraySize;
                    boss.id    = entityId;
                    boss.hp    = memoryHelper.GetMemoryValue <int>(currArrayPtr + StaticData.EnenyEnitiyHPOffset[veridx], false);
                    boss.type  = StaticData.GetBoss(entityId).Value;
                    boss.maxHp = entityMaxHp;

                    bossList.Add(boss);
                }

                currArrayPtr += entitySize;

                if (isAlive)
                {
                    ++nActiveEntities;
                }
                ++entityArraySize;
            }
        }
Example #4
0
 private void PracticeModeMapTileChangeTrigger(MapTileCoordinate oldMapTile, MapTileCoordinate newMapTile)
 {
     //if (mainContext.PracticeMode) DebugLog("Practice Mode Trigger Map Tile Change " + oldMapTile + " -> " + newMapTile);
     practiceModeContext.SendTrigger(SplitCondition.MapTileChange(oldMapTile, newMapTile));
 }