Skip to content

Conversation

@Legends0
Copy link
Collaborator

@Legends0 Legends0 commented Oct 8, 2025

With the status effects now available I was able to get the job ids and level.

EDIT: This works, but is not always reliable without a refresh of the job buff. Certain situations such as reloading the overlay cause the data to be undefined. Reloading into the instance I think refreshes the buff as does resurrecting or manually changing the phantom job. This should be kept in mind when designing triggers based on the role.

@github-actions github-actions bot added raidboss /ui/raidboss module needs-review Awaiting review labels Oct 8, 2025
@github-actions github-actions bot removed the needs-review Awaiting review label Oct 8, 2025
Co-authored-by: valarnin <valarnin@gmail.com>
@github-actions github-actions bot added the needs-review Awaiting review label Oct 8, 2025
@github-actions github-actions bot removed the needs-review Awaiting review label Oct 11, 2025
@github-actions github-actions bot added the needs-review Awaiting review label Oct 11, 2025
@Legends0
Copy link
Collaborator Author

Legends0 commented Oct 11, 2025

Some other code I was considering adding were some utility functions similar to conditions.ts, but I may just pull from them as needed:

// Return if the player has a phantom job that can dispel
// Phantom Time Mage Lv 4: Dispel
/*
const phantomCanDispel = (
  phantomJob: string,
  phantomJobLevel: number,
): boolean => {
  if (phantomJob === phantomJobData.timeMage && phantomJobLevel >= 4)
    return true;
  return false;
};
*/

// Return if the player has a phantom job that can slow
// Phantom Time Mage Lv 1: Slowga
/*
const phantomCanSlow = (
  phantomJob: string,
  phantomJobLevel: number,
): boolean => {
  if (phantomJob === phantomJobData.timeMage && phantomJobLevel >= 1)
    return true;
  return false;
};
*/

// Return if the player has a phantom job that can cleanse
// Phantom Oracle Lv 2: Recuperation
/*
const phantomCanCleanse = (
  phantomJob: string,
  phantomJobLevel: number,
): boolean => {
  if (phantomJob === phantomJobData.oracle && phantomJobLevel >= 2)
    return true;
  return false;
};
*/

// Return if the player has a phantom job that can freeze time
// Phantom Bard Lv 2: Romeo's Ballad
/*
const phantomCanFreeze = (
  phantomJob: string,
  phantomJobLevel: number,
): boolean => {
  if (phantomJob === phantomJobData.bard && phantomJobLevel >= 2)
    return true;
  return false;
};
*/

// Return if the player has a phantom job that can suspend
// Phantom Geomancer Lv 4: Suspend
/*
const phantomCanSuspend = (
  phantomJob: string,
  phantomJobLevel: number,
): boolean => {
  if (phantomJob === phantomJobData.geomancer && phantomJobLevel >= 4)
    return true;
  return false;
};
*/

// Return if the player has a phantom job that can reduce tankbuster
// Phantom Knight Lv 4: Phantom Guard + Enhanced Phantom Guard (90%)
// Phantom Knight Lv 6: Pledge
// Phantom Oracle Lv 6: Invulnerability
/*
const phantomCaresAboutTankbuster = (
  phantomJob: string,
  phantomJobLevel: number,
): boolean => {
  if (phantomJob === phantomJobData.knight && phantomJobLevel >= 4)
    return true;
  if (phantomJob === phantomJobData.oracle && phantomJobLevel >= 6)
    return true;
  return false;
};
*/

// Return if the player has a phantom job that can block physical damage
// Phantom Samurai Lv 2: Shirahadori
// Phantom Oracle Lv 6: Invulnerability
/*
const phantomCanBlockPhysical = (
  phantomJob: string,
  phantomJobLevel: number,
): boolean => {
  if (phantomJob === phantomJobData.samurai && phantomJobLevel >= 2)
    return true;
  if (phantomJob === phantomJobData.oracle && phantomJobLevel >= 6)
    return true;
  return false;
};
*/

// Return if the player has a phantom job that can reduce aoe damage
// Phantom Bard Lv 3: Mighty March (+20% MaxHP)
// Phantom Ranger Lv 6: Occult Unicorn (40k AoE Shield)
// Phantom Geomance Lv 2 may be able to use Weather with Blessed Rain, Misty Mirage, Sunbath, or Cloudy Caress effects
/*
const phantomCaresAboutAOE = (
  phantomJob: string,
  phantomJobLevel: number,
): boolean => {
  if (phantomJob === phantomJobData.bard && phantomJobLevel >= 3)
    return true;
  if (phantomJob === phantomJobData.ranger && phantomJobLevel >= 6)
    return true;
  return false;
};
*/

@Legends0
Copy link
Collaborator Author

Well, that merge didn't do what I wanted it to do and ended up touching this other branch too.

@Legends0 Legends0 force-pushed the oc-phantom-job-tracker branch from fa9fc2e to d2b7284 Compare October 12, 2025 21:08
@Legends0
Copy link
Collaborator Author

I think that this doesn't carry over into Forked Tower. The data appears to be reset on entry or between boss seals.

@Legends0
Copy link
Collaborator Author

Legends0 commented Nov 3, 2025

I think that this doesn't carry over into Forked Tower. The data appears to be reset on entry or between boss seals.

Not sure if something changed recently, but I tried more FT and the code I wrote to mask for bard in FT appeared to be working without needing to change job.

// Return if the player has a phantom job that can freeze time
// Phantom Bard Lv 2: Romeo's Ballad
const phantomCanFreeze = (
  phantomJob: string,
  phantomJobLevel: number,
): boolean => {
  if (phantomJob === phantomJobData.bard && phantomJobLevel >= 2)
    return true;
  return false;
};
...
{
      id: 'Occult Crescent Pronged Passage Ancient Aero III',
      // 6 Tower Idols cast Ancient Aero III at different times
      // Must interrupt with Romeo's Ballad all 6 at same time
      // This will count until all 12 have started casting
      type: 'StartsUsing',
      netRegex: { source: 'Tower Idol', id: 'A61F', capture: true },
      condition: (data) => {
        if (
          data.phantomJob === undefined ||
          data.phantomJobLevel === undefined ||
          phantomCanFreeze(data.phantomJob, data.phantomJobLevel)
        )
          return true;
        return false;
      },
...

Copy link

@jacob-keller jacob-keller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even with the caveat that job data can be missing due to reloads and what not, this data should still be useful.

- Neo Garula and Crescent Berserker Damage Up for Phantom Time Mage
- Forked Tower: Blood's Guardian Golem's Toxic Minerals for Phantom Oracle
- Forked Tower: Blood's Tower Idol  Ancient Aero II for Phantom Bard

Additional example helper functions in comments.
@github-actions github-actions bot added the 💬ko label Dec 9, 2025
@Legends0
Copy link
Collaborator Author

Legends0 commented Dec 9, 2025

Even with the caveat that job data can be missing due to reloads and what not, this data should still be useful.

Thanks for the feedback. I have gone ahead and added the few triggers I've had and rest of the examples before I noticed the approval.

Note: Phantom Dancer has a single-target freeze time ability, Tempting Tango. It could be pre-held, but given the random chance every cast to get the right spell, can only be rolled once every 30s, and the current use case prefers aoe version where this is single-target, I am opting not to include it for now.
@github-actions github-actions bot removed the needs-review Awaiting review label Jan 3, 2026
Copy link
Collaborator

@xiashtra xiashtra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments related to the new phantom jobs added in 7.4, but overall LGTM.

@Legends0 Legends0 merged commit ca8fdb3 into main Jan 4, 2026
10 checks passed
@Legends0 Legends0 deleted the oc-phantom-job-tracker branch January 4, 2026 02:46
@Legends0
Copy link
Collaborator Author

Legends0 commented Jan 4, 2026

Some comments related to the new phantom jobs added in 7.4, but overall LGTM.

Thanks for the comments. I have added them and adjusted the existing functions to match.

github-actions bot pushed a commit that referenced this pull request Jan 4, 2026
This works, but is not always reliable without a refresh of the
job buff. Certain situations such as reloading the overlay cause the
data to be undefined. Reloading into the instance I think refreshes the
buff as does resurrecting or manually changing the phantom job. This
should be kept in mind when designing triggers based on the role.

Triggers in Forked Tower are setup to always call out if unable to determine phantom job or phantom job level due to severity of consequences of missing a callout.

Includes some Phantom Time Mage Triggers for CEs and commented, example functions similar to what we have for Conditions for regular roles/jobs.

---------

Co-authored-by: valarnin <valarnin@gmail.com> ca8fdb3
github-actions bot pushed a commit that referenced this pull request Jan 4, 2026
This works, but is not always reliable without a refresh of the
job buff. Certain situations such as reloading the overlay cause the
data to be undefined. Reloading into the instance I think refreshes the
buff as does resurrecting or manually changing the phantom job. This
should be kept in mind when designing triggers based on the role.

Triggers in Forked Tower are setup to always call out if unable to determine phantom job or phantom job level due to severity of consequences of missing a callout.

Includes some Phantom Time Mage Triggers for CEs and commented, example functions similar to what we have for Conditions for regular roles/jobs.

---------

Co-authored-by: valarnin <valarnin@gmail.com> ca8fdb3
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.

5 participants