Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

raidboss: p12s Paradeigma 2 Tower Strategy add 'tetherbase' #5807

Merged
merged 6 commits into from
Sep 29, 2023
Merged

raidboss: p12s Paradeigma 2 Tower Strategy add 'tetherbase' #5807

merged 6 commits into from
Sep 29, 2023

Conversation

YuzukiTsuru
Copy link
Contributor

Added Paradeigma 2 Tower Strategy tetherbase, which is commonly used by Chinese players.

Solution idea:

  1. First look at the type of Anthropos generated on the sidelines, and the corresponding position of the Tether player
  2. Determine the debuff type that you have
  3. drop the tower according to the priority TH: A->B->C DPS: D->C->B

This solution avoids seeing the wrong type because the Tether player is not in place in time

@cactbotbot
Copy link
Collaborator

cactbotbot commented Sep 23, 2023

@YuzukiTsuru Thanks for your contribution! 🌵🚀

@YuzukiTsuru YuzukiTsuru changed the title raidboss:p12s Paradeigma 2 Tower Strategy add 'tetherbase' raidboss: p12s Paradeigma 2 Tower Strategy add 'tetherbase' Sep 23, 2023
@quisquous
Copy link
Owner

I watched the video and my understanding is that this looks the same as the quadrant strategy, in terms of where towers go relative to tethers. Am I understanding this correctly?

Re: A B C D. In general, I try not to put marker names in cactbot because people put markers in different places and the calls should still work without markers. If folks want to have marker locations, they can edit the cactbot config ui to say A or 1 instead of northeast. For consistency, I think it's better to just say directions.

If you want to add single tower locations, I think it would be better to implement this as an additional config option so that it would work with both quadrant and clockwise strategies. Rather than embedding "A+NW", it would use the previous "NW" logic, but could find the set of positions at the end and pull out the correct one for the role. This option would be a choice between "default (call out two locations)" and "support NE+clockwise". Does that make sense?

@YuzukiTsuru
Copy link
Contributor Author

The quadrant is bassed on the tether player, but the tetherbase is based on the Anthropos, I'm thinking of solving this problem in a way that's closer to the actual processing logic.

A B C D it is for internal use only and will not be displayed. Since this strategy is strongly based on waymark, I think it's easier to understand using ABCD here (in code).

The A+NW method is used here to distinguish two different NW. According to the original quadrant method, only the target can be dropped on NW, and the actual position of Anthropos is not known (and it is not necessary to know). However, this strategy is based on the location of Anthropos, so it is necessary to determine the actual location of Anthropos. And for this strategy only.

@quisquous
Copy link
Owner

quisquous commented Sep 24, 2023

The quadrant is bassed on the tether player, but the tetherbase is based on the Anthropos, I'm thinking of solving this problem in a way that's closer to the actual processing logic.

image

I am not sure I understand what you are saying. This appears to be the same logic as quadrant, in that if there is a NNW light add, then there needs to be a dark SW tower and if there is a NNE light add then there needs to be a dark SE tower instead. This seems to be the same strategy.

A B C D it is for internal use only and will not be displayed. Since this strategy is strongly based on waymark, I think it's easier to understand using ABCD here (in code).

Oh, I see. A B C D is just a way to do priority. I think it could be done in a simpler manner if that's true. I was trying to propose a second separate config option to do the priority ordering, and do the sorting after the tower locations had been found. Something like this:

          const engravement1Keys: string[] = [];
          data.engravement1BeamsPosMap.forEach((value: string, key: string) => {
            if (value === 'light' && matches.effectId === engravementIdMap.lightTower)
              engravement1Keys.push(key);
            else if (value === 'dark' && matches.effectId === engravementIdMap.darkTower)
              engravement1Keys.push(key);
          });

          const outputMap: { [dir: string]: string } = {
            NW: output.northwest!(),
            NE: output.northeast!(),
            SE: output.southeast!(),
            SW: output.southwest!(),
          } as const;

          const [key0, key1] = engravement1Keys;
          if (key0 === undefined || key1 === undefined)
            return;

          // This is a new trigger config that would be need to be added.
          if (data.triggerSetConfig.engravement1SortOrder === 'SupportNEClockwise') {
            // By doing it this way, we could support multiple sort orders easily in the future.
            // Also having a config option lets this apply to both quadrant and clockwise strategies,
            // and doesn't intermix "priority" with "tower location" logic.
            const supportOrder = ['NE', 'SE', 'SW', 'NW'];
            const idx0 = supportOrder.indexOf(key0);
            const idx1 = supportOrder.indexOf(key1);
            const supportPreferKey0 = idx0 < idx1;
            const isSupport = data.role !== 'dps';
            const useKey0 = isSupport && supportPreferKey0 || !isSupport && !supportPreferKey0;
            const myKey = useKey0 ? key0 : key1;
            if (matches.effectId === engravementIdMap.lightTower)
              return output.lightTowerOneSide!({ pos1: outputMap[myKey] });
            return output.darkTowerOneSide!({ pos1: outputMap[myKey] });

          } else if (data.triggerSetConfig.engravement1SortOrder === 'default') {
            if (matches.effectId === engravementIdMap.lightTower) {
              return output.lightTowerSide!({
                pos1: outputMap[key0],
                pos2: outputMap[key1],
              });
            }

            return output.darkTowerSide!({
              pos1: outputMap[key0],
              pos2: outputMap[key1],
            });
          }

@Souma-Sumire
Copy link
Contributor

I think we cannot sort by tower positions because a dark SW tower could be either an NNW light add or an EES light add.

I gave two examples to demonstrate the results after sorting by the source, and you can see that if we use tower sorting, the order of these two results is exactly opposite.

image
image

@YuzukiTsuru
Copy link
Contributor Author

It seems impossible to simply sort the position of the tower, previously thought that a new collector could be added here to collect functions and tower colors, but it is possible to modify the current matching conditions.

@quisquous
Copy link
Owner

Ohhhhhhhhh I see, the sorting is based on where the add is and not where the location is. Wild. (It's still sad to me that clockwise isn't a more popular strategy because it has the same advantage as looking at the tether base but you also don't need to look at which side of the line the add is on, only the tether color. Anyway~~~.)

Ok, then I'd rather still do something like this, where you annotate the beam data with the location explicitly, rather than having one of the paths have different values in the map that have to be processed. Sorry to be picky, I just think this is getting rather complicated (especially if somebody ever wants to add a fourth one or different sorting), and so I want to try to keep it easier to follow along.

What about something like this code. It keeps the sorting at the end and doesn't duplicate the tower location finding. It also only finds the towers that are valid for the current player rather than finding them all, which simplifies a lot.

      alertText: (data, matches, output) => {
        data.engravement1Towers.push(matches.target);

        if (data.me !== matches.target)
          return;

        // if Only notify tower color
        if (data.triggerSetConfig.engravement1DropTower === 'tower') {
          if (matches.effectId === engravementIdMap.lightTower)
            return output.lightTower!();
          return output.darkTower!();
        }

        const locations = ['NE', 'SW', 'SE', 'NW'] as const;
        type TowerLocation = typeof locations[number];
        type CloneLocation = 'NNW' | 'NNE' | 'ENE' | 'ESE' | 'SSE' | 'SSW' | 'WNW' | 'WSW';
        type TowerData = {
          location: TowerLocation;
          clone: CloneLocation;
        };
        const towerList: TowerData[] = [];
        const towerStrategy = data.triggerSetConfig.engravement1DropTower;

        for (const combatant of data.combatantData) {
          const x = combatant.PosX;
          const y = combatant.PosY;

          const combatantId = combatant.ID;
          if (combatantId === undefined)
            return;

          const tempColor = data.engravement1TetherPlayers[combatantId.toString(16).toUpperCase()];
          const color = tempColor === 'light' ? 'dark' : 'light';

          const isCorrectColor = color === 'light' && matches.effectId === engravementIdMap.lightTower ||
            color === 'dark' && matches.effectId === engravementIdMap.darkTower;
          if (!isCorrectColor)
            continue;

          if (towerStrategy === 'quadrant' || towerStrategy === 'tetherbase') {
            if (x < 80 && y < 100) { // WNW: x = 75 && y = 97
              towerList.push({ location: 'NE', clone: 'WNW' });
            } else if (x < 100 && y < 80) { // NNW: x = 97 && y = 75
              towerList.push({ location: 'SW', clone: 'NNW' });
            } else if (x > 100 && y < 80) { // NNE: x = 103 && y = 75
              towerList.push({ location: 'SE', clone: 'NNE' });
            } else if (x > 120 && y < 100) { // ENE: x = 125 && y = 97
              towerList.push({ location: 'NW', clone: 'ENE' });
            } else if (x > 120 && y > 100) { // ESE: x = 125 && y = 103
              towerList.push({ location: 'SW', clone: 'ESE' });
            } else if (x > 100 && y > 120) { // SSE: x = 103 && y = 125
              towerList.push({ location: 'NE', clone: 'SSE' });
            } else if (x < 100 && y > 120) { // SSW: x = 97 && y = 125
              towerList.push({ location: 'NW', clone: 'SSW' });
            } else if (x < 80 && y > 100) { // WSW: x = 75 && y = 103
              towerList.push({ location: 'SE', clone: 'WSW' });
            }
          } else if (data.triggerSetConfig.engravement1DropTower === 'clockwise') {
            // Tether stretches across and tower is clockwise; e.g. N add stretches S, and tower is SW.
            if (x < 80 && y < 100) { // WNW: x = 75 && y = 97
              towerList.push({ location: 'SE', clone: 'WNW' });
            } else if (x < 100 && y < 80) { // NNW: x = 97 && y = 75
              towerList.push({ location: 'SW', clone: 'NNW' });
            } else if (x > 100 && y < 80) { // NNE: x = 103 && y = 75
              towerList.push({ location: 'SW', clone: 'NNE' });
            } else if (x > 120 && y < 100) { // ENE: x = 125 && y = 97
              towerList.push({ location: 'NW', clone: 'ENE' });
            } else if (x > 120 && y > 100) { // ESE: x = 125 && y = 103
              towerList.push({ location: 'NW', clone: 'ESE' });
            } else if (x > 100 && y > 120) { // SSE: x = 103 && y = 125
              towerList.push({ location: 'NE', clone: 'SSE' });
            } else if (x < 100 && y > 120) { // SSW: x = 97 && y = 125
              towerList.push({ location: 'NE', clone: 'SSW' });
            } else if (x < 80 && y > 100) { // WSW: x = 75 && y = 103
              towerList.push({ location: 'SE', clone: 'WSW' });
            }
          }
        }

        // Now use strategy and towerList (which only contains the correct color for the player)
        // to call out two spots or sort down to one spot.

        const outputMap: { [dir in TowerLocation]: string } = {
          NW: output.northwest!(),
          NE: output.northeast!(),
          SE: output.southeast!(),
          SW: output.southwest!(),
        } as const;

        const [tower0, tower1] = towerList;
        if (tower0 === undefined || tower1 === undefined)
          return;

        if (towerStrategy === 'clockwise' || towerStrategy === 'quadrant') {
          if (matches.effectId === engravementIdMap.lightTower) {
            return output.lightTowerSide!({
              pos1: outputMap[tower0.location],
              pos2: outputMap[tower1.location],
            });
          }

          return output.darkTowerSide!({
            pos1: outputMap[tower0.location],
            pos2: outputMap[tower1.location],
          });
        } else if (towerStrategy === 'tetherbase') {
          // TODO: do some sorting based on tower01.clone
        }

@YuzukiTsuru
Copy link
Contributor Author

It seems to work. I'll test it later.

@YuzukiTsuru
Copy link
Contributor Author

I tested it and it seems to works for me.

@quisquous quisquous merged commit 126385c into quisquous:main Sep 29, 2023
@quisquous
Copy link
Owner

Sorry for the extra work. I think the end result will make it much better to add another strategy in the future if we need to. Thank you!

github-actions bot pushed a commit that referenced this pull request Sep 29, 2023
…rbase' (#5807)

Added Paradeigma 2 Tower Strategy tetherbase, which is commonly used by
Chinese players.

- [【【菓子】FF14万魔殿天狱篇零式4层 P12S超详解攻略】
](https://www.bilibili.com/video/BV1vF411S7oL)

Solution idea:
1. First look at the type of Anthropos generated on the sidelines, and
the corresponding position of the Tether player
2. Determine the debuff type that you have
3. drop the tower according to the priority TH: A->B->C DPS: D->C->B

This solution avoids seeing the wrong type because the Tether player is
not in place in time 126385c
github-actions bot pushed a commit that referenced this pull request Sep 29, 2023
…rbase' (#5807)

Added Paradeigma 2 Tower Strategy tetherbase, which is commonly used by
Chinese players.

- [【【菓子】FF14万魔殿天狱篇零式4层 P12S超详解攻略】
](https://www.bilibili.com/video/BV1vF411S7oL)

Solution idea:
1. First look at the type of Anthropos generated on the sidelines, and
the corresponding position of the Tether player
2. Determine the debuff type that you have
3. drop the tower according to the priority TH: A->B->C DPS: D->C->B

This solution avoids seeing the wrong type because the Tether player is
not in place in time 126385c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants