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

Convert GES to stager #556

Merged
merged 5 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 21 additions & 56 deletions src/scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
import {IntakeRejectionEngine} from "./hunt-filter/engine";
import {ConsoleLogger, LogLevel} from './util/logger';
import {getUnixTimestamp} from "./util/time";
import * as successHandlers from './modules/ajax-handlers';
import {parseHgInt} from "./util/number";
import {HornHud} from './util/HornHud';
import * as successHandlers from './modules/ajax-handlers';
import * as detailers from './modules/details';
import * as stagers from './modules/stages';
import * as stagingFuncs from './modules/stages/legacy';
import * as detailingFuncs from './modules/details/legacy';

(function () {
Expand Down Expand Up @@ -456,8 +456,8 @@ import * as detailingFuncs from './modules/details/legacy';
}

/**
* @param {Object <string, any>} pre_response The object obtained prior to invoking `activeturn.php`.
* @param {Object <string, any>} post_response Parsed JSON representation of the response from calling activeturn.php
* @param {import("./types/hg").HgResponse} pre_response The object obtained prior to invoking `activeturn.php`.
* @param {import("./types/hg").HgResponse} post_response Parsed JSON representation of the response from calling activeturn.php
*/
function recordHuntWithPrehuntUser(pre_response, post_response) {
logger.debug("In recordHuntWithPrehuntUser pre and post:", pre_response, post_response);
Expand Down Expand Up @@ -559,10 +559,10 @@ import * as detailingFuncs from './modules/details/legacy';

/**
*
* @param {Object<string, any>} user A the main user object (pre or post) used to populate the message
* @param {Object<string, any>} user_post The post-hunt user object
* @param {Object <string, any>} hunt Journal entry corresponding with the hunt
* @returns
* @param {import("./types/hg").User} user A the main user object (pre or post) used to populate the message
* @param {import("./types/hg").User} user_post The post-hunt user object
* @param {import("./types/hg").JournalMarkup} hunt Journal entry corresponding with the hunt
* @returns {import("./types/mhct").IntakeMessage | undefined}
*/
function createIntakeMessage(user, user_post, hunt) {
// Obtain the main hunt information from the journal entry and user objects.
Expand Down Expand Up @@ -739,10 +739,12 @@ import * as detailingFuncs from './modules/details/legacy';

/**
* Find the active journal entry, and handle supported "bonus journals" such as the Relic Hunter attraction.
* @param {Object <string, any>} hunt_response The JSON response returned from a horn sound.
* @returns {Object <string, any>} The journal entry corresponding to the active hunt.
* @param {import("./types/hg").HgResponse} hunt_response The JSON response returned from a horn sound.
* @param {number} max_old_entry_id
* @returns {import("./types/hg").JournalMarkup | null} The journal entry corresponding to the active hunt.
*/
function parseJournalEntries(hunt_response, max_old_entry_id) {
/** @type {import("./types/hg").JournalMarkup & Object<string, unknown>} */
let journal = {};
const more_details = {};
more_details.hunt_count = 0;
Expand Down Expand Up @@ -1014,19 +1016,16 @@ import * as detailingFuncs from './modules/details/legacy';

/**
* Initialize the message with main hunt details.
* @param {Object <string, any>} journal The journal entry corresponding to the active hunt.
* @param {Object <string, any>} user The user state object, when the hunt was invoked (pre-hunt).
* @param {Object <string, any>} user_post The user state object, after the hunt.
* @returns {Object <string, any> | null} The message object, or `null` if an error occurred.
* @param {import("./types/hg").JournalMarkup} journal The journal entry corresponding to the active hunt.
* @param {import("./types/hg").User} user The user state object, when the hunt was invoked (pre-hunt).
* @param {import("./types/hg").User} user_post The user state object, after the hunt.
* @returns {import("@scripts/types/mhct").IntakeMessage | null} The message object, or `null` if an error occurred.
*/
function createMessageFromHunt(journal, user, user_post) {
/** @type {import("./types/mhct").IntakeMessage} */
const message = {};
const debug_logs = [];

// Entry ID
message.entry_id = journal.render_data.entry_id;

// Entry Timestamp
message.entry_timestamp = journal.render_data.entry_timestamp;

// Location
Expand All @@ -1038,36 +1037,20 @@ import * as detailingFuncs from './modules/details/legacy';
name: user.environment_name,
id: user.environment_id,
};
if (user_post.environment_id != user.environment_id) {
debug_logs.push(`User auto-traveled from ${user.environment_name} to ${user_post.environment_name}`);
}

// Shield (true / false)
message.shield = user.has_shield;

// Total Power, Luck, Attraction
message.total_power = user.trap_power;
if (user_post.trap_power !== user.trap_power) {
debug_logs.push(`User setup power changed from ${user.trap_power} to ${user_post.trap_power}`);
}

message.total_luck = user.trap_luck;
if (user_post.trap_luck !== user.trap_luck) {
debug_logs.push(`User setup luck changed from ${user.trap_luck} to ${user_post.trap_luck}`);
}

message.attraction_bonus = Math.round(user.trap_attraction_bonus * 100);
if (user_post.trap_attraction_bonus !== user.trap_attraction_bonus) {
debug_logs.push(`User setup attraction bonus changed from ${user.trap_attraction_bonus} to ${user_post.trap_attraction_bonus}`);
}

// Setup components
const components = [
{prop: 'weapon', message_field: 'trap', required: true, replacer: / trap$/i},
{prop: 'base', message_field: 'base', required: true, replacer: / base$/i},
{prop: 'bait', message_field: 'cheese', required: true, replacer: / cheese$/i},
{prop: 'trinket', message_field: 'charm', required: false, replacer: / charm$/i},
];

// Setup components
// All pre-hunt users must have a weapon, base, and cheese.
const missing = components.filter(component => component.required === true
&& !Object.prototype.hasOwnProperty.call(user, `${component.prop}_name`)
Expand All @@ -1087,13 +1070,10 @@ import * as detailingFuncs from './modules/details/legacy';
name: '',
}
: {
id: user[prop_id],
// Make sure any strumbers are converted to actual numbers
id: parseHgInt(user[prop_id]),
name: item_name.replace(component.replacer, ''),
};

if (item_name !== user_post[prop_name]) {
debug_logs.push(`User ${component.message_field} changed: Was '${item_name}' and is now '${user_post[prop_name] || "None"}'`);
}
});

// Caught / Attracted / FTA'd
Expand All @@ -1118,8 +1098,6 @@ import * as detailingFuncs from './modules/details/legacy';
.replace(/ mouse$/i, ''); // Remove " [Mm]ouse" if it is not a part of the name (e.g. Dread Pirate Mousert)
}

debug_logs.forEach(log_message => logger.debug(log_message));

return message;
}

Expand Down Expand Up @@ -1178,13 +1156,6 @@ import * as detailingFuncs from './modules/details/legacy';
}
}

/** @type {Object <string, Function>} */
const location_stage_lookup = {
"Festive Comet": stagingFuncs.addFestiveCometStage,
"Frozen Vacant Lot": stagingFuncs.addFestiveCometStage,
"Gnawnian Express Station": stagingFuncs.addTrainStage,
};

/** @type {Object<string, import("./modules/stages/stages.types").IStager>} */
const location_stager_lookup = {};
for (const stager of stagers.stageModules) {
Expand All @@ -1199,12 +1170,6 @@ import * as detailingFuncs from './modules/details/legacy';
* @param {Object <string, any>} hunt The journal entry corresponding to the active hunt
*/
function addStage(message, user, user_post, hunt) {
// legacy staging funcs
const stage_func = location_stage_lookup[user.environment_name];
if (stage_func) {
stage_func(message, user, user_post, hunt);
}

// IStagers
const stager = location_stager_lookup[user.environment_name];
if (stager) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {type User} from '@scripts/types/hg';
import {type IntakeMessage} from '@scripts/types/mhct';
import {TroubleArea, type BoardingPhase} from '@scripts/types/quests/gnawnianExpressStation';
import {type IStager} from '../stages.types';

export class GnawnianExpressStationStager implements IStager {
readonly environment: string = 'Gnawnian Express Station';

/**
* Report on the unique minigames in each sub-location. Reject hunts for which the train
* moved / updated / departed, as the hunt stage is ambiguous.
*/
addStage(message: IntakeMessage, userPre: User, userPost: User, journal: unknown): void {
const quest = userPre.quests.QuestTrainStation;
const final_quest = userPost.quests.QuestTrainStation;

if (!quest || !final_quest) {
throw new Error('QuestTrainStation is undefined');
}

if (quest.on_train !== final_quest.on_train) {
throw new Error('Skipping hunt due to server-side train stage change');
}


// Pre- & post-hunt user object agree on train & phase statuses.
if (!quest.on_train || !final_quest.on_train) {
message.stage = 'Station';
return;
}

if (quest.current_phase !== final_quest.current_phase) {
throw new Error('Skipping hunt due to server-side train stage change');
}

if (quest.current_phase === 'supplies') {
let stage = '1. Supply Depot';
if (quest.minigame && quest.minigame.supply_hoarder_turns > 0) {
// More than 0 (aka 1-5) Hoarder turns means a Supply Rush is active
stage += ' - Rush';
} else {
stage += ' - No Rush';
if (userPre.trinket_name === 'Supply Schedule Charm') {
stage += ' + SS Charm';
}
}
message.stage = stage;
} else if (quest.current_phase === 'boarding') {
let stage = '2. Raider River';
// Raider River has an additional server-side state change.
const area = quest.minigame.trouble_area;
const final_area = (final_quest as BoardingPhase).minigame.trouble_area;

if (area !== final_area) {
throw new Error('Skipping hunt during server-side trouble area change');
}

const charm_id = message.charm?.id ?? -1;
const area_to_charm: Record<TroubleArea, number> = {
'door': 1210,
'rails': 1211,
'roof': 1212,
};
const has_correct_charm = area_to_charm[area] === charm_id;
if (has_correct_charm) {
stage += ' - Defending Target';
} else if ([1210, 1211, 1212].includes(charm_id)) {
stage += ' - Defending Other';
} else {
stage += ' - Not Defending';
}
message.stage = stage;
} else if (quest.current_phase === 'bridge_jump') {
let stage = '3. Daredevil Canyon';
if (userPre.trinket_name === 'Magmatic Crystal Charm') {
stage += ' - Magmatic Crystal';
} else if (userPre.trinket_name === 'Black Powder Charm') {
stage += ' - Black Powder';
} else if (userPre.trinket_name === 'Dusty Coal Charm') {
stage += ' - Dusty Coal';
} else {
stage += ' - No Fuelers';
}
message.stage = stage;
}
}
}
2 changes: 2 additions & 0 deletions src/scripts/modules/stages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {ForewordFarmStager} from './environments/forewardFarm';
import {FortRoxStager} from './environments/fortRox';
import {FungalCavernStager} from './environments/fungalCavern';
import {FuromaRiftStager} from './environments/furomaRift';
import {GnawnianExpressStationStager} from './environments/gnawnianExpressStation';
import {HarbourStager} from './environments/harbour';
import {IcebergStager} from './environments/iceberg';
import {IceFortressStager} from './environments/iceFortress';
Expand Down Expand Up @@ -49,6 +50,7 @@ const stageModules: IStager[] = [
new FortRoxStager(),
new FungalCavernStager(),
new FuromaRiftStager(),
new GnawnianExpressStationStager(),
new HarbourStager(),
new IcebergStager(),
new IceFortressStager(),
Expand Down
104 changes: 0 additions & 104 deletions src/scripts/modules/stages/legacy.js

This file was deleted.

Loading