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

Add function to fix some message formatting #6145

Merged
merged 5 commits into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 2 additions & 2 deletions docs/src/content/docs/osb/combat-achievements.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Rewards can be claimed by simply using [[/ca claim]] after completing a new tier
| Aberrant Spectre | Noxious Foe | 1x Aberrant Spectre KC |
| Barrows | Barrows Novice | 10x Barrows KC |
| Barrows | Defence? What Defence? | 1 in 1 chance per kill |
| Black Dragon | Big, Black and Fiery | ONE of the following requirements must be met: 1x King Black Dragon KC, Kill Count Requirement: 1x Black Dragon KC. |
| Black Dragon | Big, Black and Fiery | ONE of the following requirements must be met: 1x King Black Dragon KC or Kill Count Requirement: 1x Black Dragon KC. |
| Bloodveld | The Demonic Punching Bag | 1x Bloodveld KC |
| Bryophyta | Preparation Is Key | 1 in 15 chance per kill |
| Bryophyta | Fighting as Intended II | 1 in 1 chance per kill |
Expand All @@ -122,7 +122,7 @@ Rewards can be claimed by simply using [[/ca claim]] after completing a new tier
| Obor | Obor Novice | 1x Obor KC |
| Obor | Fighting as Intended | 1 in 1 chance per kill |
| Obor | Sleeping Giant | 1 in 10 chance per kill |
| Other | Into the Den of Giants | 1x Fire Giant KC, 1x Moss giant KC, 1x Hill Giant KC |
| Other | Into the Den of Giants | 1x Hill Giant KC, 1x Moss giant KC and 1x Fire Giant KC |
| Sarachnis | Sarachnis Novice | 10x Sarachnis KC |
| Scurrius | Sit Rat | 1 in 1 chance per kill |
| Scurrius | Scurrius Novice | 1x Scurrius KC |
Expand Down
22 changes: 13 additions & 9 deletions src/lib/colosseum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { QuestID } from './minions/data/quests';
import { ChargeBank } from './structures/Bank';
import type { ItemBank, Skills } from './types';
import type { ColoTaskOptions } from './types/minions';
import { joinStrings } from './util';
import addSubTaskToActivityTask from './util/addSubTaskToActivityTask';
import { formatSkillRequirements, itemNameFromID } from './util/smallUtils';
import { updateBankSetting } from './util/updateBankSetting';
Expand Down Expand Up @@ -517,23 +518,26 @@ export async function colosseumCommand(user: MUser, channelID: string) {
for (const items of objectValues(gearNeeded)) {
if (!items) continue;
if (!items.some(g => gear.hasEquipped(g))) {
return `You need one of these equipped in your ${gearType} setup to enter the Colosseum: ${items
.map(itemNameFromID)
.join(', ')}.`;
return `You need one of these equipped in your ${gearType} setup to enter the Colosseum: ${joinStrings(
items.map(itemNameFromID),
'or'
)}.`;
}
}
}

if (!meleeWeapons.some(i => user.gear.melee.hasEquipped(i, true, true))) {
return `You need one of these equipped in your melee setup to enter the Colosseum: ${meleeWeapons
.map(itemNameFromID)
.join(', ')}.`;
return `You need one of these equipped in your melee setup to enter the Colosseum: ${joinStrings(
meleeWeapons.map(itemNameFromID),
'or'
)}.`;
}

if (!rangeWeapons.some(i => user.gear.range.hasEquipped(i, true, true))) {
return `You need one of these equipped in your range setup to enter the Colosseum: ${rangeWeapons
.map(itemNameFromID)
.join(', ')}.`;
return `You need one of these equipped in your range setup to enter the Colosseum: ${joinStrings(
rangeWeapons.map(itemNameFromID),
'or'
)}.`;
}

const messages: string[] = [];
Expand Down
8 changes: 4 additions & 4 deletions src/lib/combat_achievements/combatAchievements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { deepClone, notEmpty, roll, sumArr } from 'e';
import type { Item } from 'oldschooljs';
import type { Requirements } from '../structures/Requirements';
import type { ActivityTaskData, TOAOptions } from '../types/minions';
import { assert } from '../util';
import { assert, joinStrings } from '../util';
import getOSItem from '../util/getOSItem';
import type { TripFinishEffect } from '../util/handleTripFinish';
import { easyCombatAchievements } from './easy';
Expand Down Expand Up @@ -209,9 +209,9 @@ export const combatAchievementTripEffect = async ({ data, messages, user }: Para

if (completedTasks.length > 0) {
messages.push(
`${users.length === 1 ? 'You' : `${user}`} completed the ${completedTasks
.map(i => i.name)
.join(', ')} Combat Achievement Task${completedTasks.length > 1 ? 's' : ''}!`
`${users.length === 1 ? 'You' : `${user}`} completed the ${joinStrings(
completedTasks.map(i => i.name)
)} Combat Achievement Task${completedTasks.length > 1 ? 's' : ''}!`
);
await user.update({
completed_ca_task_ids: {
Expand Down
7 changes: 5 additions & 2 deletions src/lib/diaries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Skillcapes from './skilling/skillcapes';
import { courses } from './skilling/skills/agility';
import { MUserStats } from './structures/MUserStats';
import type { Skills } from './types';
import { joinStrings } from './util';
import getOSItem from './util/getOSItem';
import { formatSkillRequirements, hasSkillReqs, itemNameFromID } from './util/smallUtils';

Expand Down Expand Up @@ -53,15 +54,17 @@ export function userhasDiaryTierSync(
const unownedItems = tier.ownedItems.filter(i => !bank.has(i));
if (unownedItems.length > 0) {
canDo = false;
reasons.push(`You don't own ${unownedItems.map(itemNameFromID).join(', ')}`);
reasons.push(`You don't own ${joinStrings(unownedItems.map(itemNameFromID), 'or')}`);
}
}

if (tier.collectionLogReqs) {
const unownedItems = tier.collectionLogReqs.filter(i => !cl.has(i));
if (unownedItems.length > 0) {
canDo = false;
reasons.push(`You don't have **${unownedItems.map(itemNameFromID).join(', ')}** in your collection log`);
reasons.push(
`You don't have **${joinStrings(unownedItems.map(itemNameFromID), 'or')}** in your collection log`
);
}
}

Expand Down
7 changes: 4 additions & 3 deletions src/lib/musicCape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { MinigameName } from './settings/minigames';
import { Minigames } from './settings/minigames';
import type { RequirementFailure } from './structures/Requirements';
import { Requirements } from './structures/Requirements';
import { joinStrings } from './util';

export const musicCapeRequirements = new Requirements()
.add({
Expand Down Expand Up @@ -120,7 +121,7 @@ export const musicCapeRequirements = new Requirements()
if (notDoneRunes.length > 0) {
return [
{
reason: `You need to Runecraft these runes at least once: ${notDoneRunes.join(', ')}.`
reason: `You need to Runecraft these runes at least once: ${joinStrings(notDoneRunes)}.`
}
];
}
Expand Down Expand Up @@ -180,7 +181,7 @@ export const musicCapeRequirements = new Requirements()

if (minigamesNotDone.length > 0) {
results.push({
reason: `You need to do these minigames at least once: ${minigamesNotDone.slice(0, 5).join(', ')}.`
reason: `You need to do these minigames at least once: ${joinStrings(minigamesNotDone.slice(0, 5))}.`
});
}

Expand All @@ -197,7 +198,7 @@ export const musicCapeRequirements = new Requirements()
if (!uniqueTracks.some(i => eventBank[i.id])) {
const tracksNeeded = RandomEvents.filter(i => i.uniqueMusic).map(i => i.name);
results.push({
reason: `You need to do one of these random events: ${tracksNeeded.join(', ')}.`
reason: `You need to do one of these random events: ${joinStrings(tracksNeeded, 'or')}.`
});
}
return results;
Expand Down
61 changes: 31 additions & 30 deletions src/lib/structures/Requirements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type { RobochimpUser } from '../roboChimp';
import { type MinigameName, minigameColumnToNameMap } from '../settings/minigames';
import Agility from '../skilling/skills/agility';
import type { Skills } from '../types';
import { itemNameFromID } from '../util';
import { itemNameFromID, joinStrings } from '../util';
import { MUserStats } from './MUserStats';

export interface RequirementFailure {
Expand Down Expand Up @@ -63,27 +63,29 @@ export class Requirements {
const requirementParts: (string | string[])[] = [];
if ('skillRequirements' in req) {
requirementParts.push(
`Required Skills: ${objectEntries(req.skillRequirements)
.map(([skill, level]) => `Level ${level} ${skill}`)
.join(', ')}`
`Required Skills: ${joinStrings(
objectEntries(req.skillRequirements).map(([skill, level]) => `Level ${level} ${skill}`)
)}`
);
}

if ('clRequirement' in req) {
requirementParts.push(
`Items Must Be in CL: ${
Array.isArray(req.clRequirement)
? req.clRequirement.map(itemNameFromID).join(', ')
? joinStrings(req.clRequirement.map(itemNameFromID))
: req.clRequirement.toString()
}`
);
}

if ('kcRequirement' in req) {
requirementParts.push(
`Kill Count Requirement: ${Object.entries(req.kcRequirement)
.map(([k, v]) => `${v}x ${effectiveMonsters.find(i => i.id === Number(k))?.name} KC`)
.join(', ')}`
`Kill Count Requirement: ${joinStrings(
Object.entries(req.kcRequirement).map(
([k, v]) => `${v}x ${effectiveMonsters.find(i => i.id === Number(k))?.name} KC`
)
)}`
);
}

Expand All @@ -93,9 +95,11 @@ export class Requirements {

if ('lapsRequirement' in req) {
requirementParts.push(
`Agility Course Laps Requirements: ${Object.entries(req.lapsRequirement)
.map(([k, v]) => `${v}x laps of ${Agility.Courses.find(i => i.id === Number(k))?.name}`)
.join(', ')}.`
`Agility Course Laps Requirements: ${joinStrings(
Object.entries(req.lapsRequirement).map(
([k, v]) => `${v}x laps of ${Agility.Courses.find(i => i.id === Number(k))?.name}`
)
)}.`
);
}

Expand All @@ -105,9 +109,9 @@ export class Requirements {

if ('minigames' in req) {
requirementParts.push(
`Minigame Requirements: ${Object.entries(req.minigames)
.map(([k, v]) => `${v}x ${minigameColumnToNameMap.get(k)} KC`)
.join(', ')}.`
`Minigame Requirements: ${joinStrings(
Object.entries(req.minigames).map(([k, v]) => `${v}x ${minigameColumnToNameMap.get(k)} KC`)
)}.`
);
}

Expand All @@ -117,15 +121,15 @@ export class Requirements {

if ('diaryRequirement' in req) {
requirementParts.push(
`Achievement Diary Requirement: ${req.diaryRequirement
.map(i => `${i[1]} ${diaries.find(d => d.id === i[0])?.name}`)
.join(', ')}`
`Achievement Diary Requirement: ${joinStrings(
req.diaryRequirement.map(i => `${i[1]} ${diaries.find(d => d.id === i[0])?.name}`)
)}`
);
}

if ('OR' in req) {
const subResults = req.OR.map(i => this.formatRequirement(i));
requirementParts.push(`ONE of the following requirements must be met: ${subResults.join(', ')}.`);
requirementParts.push(`ONE of the following requirements must be met: ${joinStrings(subResults, 'or')}.`);
}

if ('name' in req && req.name) {
Expand Down Expand Up @@ -182,18 +186,15 @@ export class Requirements {
}
if (insufficientLevels.length > 0) {
results.push({
reason: `You need these stats: ${insufficientLevels.join(', ')}.`
reason: `You need these stats: ${joinStrings(insufficientLevels)}.`
});
}
}

if ('clRequirement' in requirement) {
if (!user.cl.has(requirement.clRequirement)) {
const missingItems = Array.isArray(requirement.clRequirement)
? requirement.clRequirement
.filter(i => !user.cl.has(i))
.map(itemNameFromID)
.join(', ')
? joinStrings(requirement.clRequirement.filter(i => !user.cl.has(i)).map(itemNameFromID))
: requirement.clRequirement.clone().remove(user.cl);
results.push({
reason: `You need ${missingItems} in your CL.`
Expand All @@ -213,7 +214,7 @@ export class Requirements {
}
if (missingMonsterNames.length > 0) {
results.push({
reason: `You need the following KC's: ${missingMonsterNames.join(', ')}.`
reason: `You need the following KC's: ${joinStrings(missingMonsterNames)}.`
});
}
}
Expand Down Expand Up @@ -257,7 +258,7 @@ export class Requirements {
}
if (insufficientMinigames.length > 0) {
results.push({
reason: `You need these minigames scores: ${insufficientMinigames.join(', ')}.`
reason: `You need these minigames scores: ${joinStrings(insufficientMinigames)}.`
});
}
}
Expand Down Expand Up @@ -286,9 +287,9 @@ export class Requirements {
.filter(i => !i.has);
if (unmetDiaries.length > 0) {
results.push({
reason: `You need to finish these achievement diaries: ${unmetDiaries
.map(i => i.tierName)
.join(', ')}.`
reason: `You need to finish these achievement diaries: ${joinStrings(
unmetDiaries.map(i => i.tierName)
)}.`
});
}
}
Expand All @@ -308,7 +309,7 @@ export class Requirements {
if (!orResults.some(i => i.length === 0)) {
results.push({
reason: `You need to meet one of these requirements:\n${orResults.map((res, index) => {
return `${index + 1}. ${res.join(', ')})}`;
return `${index + 1}. ${joinStrings(res, 'or')})}`;
})}`
});
}
Expand Down Expand Up @@ -371,7 +372,7 @@ GROUP BY type;`,
hasAll: results.filter(i => i.result.length !== 0).length === 0,
reasonsDoesnt: results
.filter(i => i.result.length > 0)
.map(i => `${i.requirement.name}: ${i.result.map(t => t.reason).join(', ')}`),
.map(i => `${i.requirement.name}: ${joinStrings(i.result.map(t => t.reason))}`),
rendered: `- ${flatReasons
.filter(i => i.reason)
.map(i => i.reason)
Expand Down
28 changes: 23 additions & 5 deletions src/lib/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,14 @@ export function formatItemCosts(consumable: Consumable, timeToFinish: number) {
}

if (multiple) {
str.push(subStr.join(', '));
str.push(joinStrings(subStr));
} else {
str.push(subStr.join(''));
}
}

if (consumables.length > 1) {
return `(${str.join(' OR ')})`;
return `(${joinStrings(str, 'or')})`;
}

return str.join('');
Expand All @@ -205,10 +205,10 @@ export function formatPohBoosts(boosts: POHBoosts) {
bonusStr.push(`${boostPercent}% for ${name}`);
}

slotStr.push(`${slot.replace(/\b\S/g, t => t.toUpperCase())}: (${bonusStr.join(' or ')})\n`);
slotStr.push(`${slot.replace(/\b\S/g, t => t.toUpperCase())}: (${joinStrings(bonusStr, 'or')})\n`);
}

return slotStr.join(', ');
return joinStrings(slotStr);
}

export type PaginatedMessagePage = MessageEditOptions | (() => Promise<MessageEditOptions>);
Expand Down Expand Up @@ -389,7 +389,7 @@ export function checkRangeGearWeapon(gear: Gear) {
if (!projectileCategory[1].items.includes(ammo.item)) {
return `You have invalid ammo for your equipped weapon. For ${
projectileCategory[0]
}-based weapons, you can use: ${projectileCategory[1].items.map(itemNameFromID).join(', ')}.`;
}-based weapons, you can use: ${joinStrings(projectileCategory[1].items.map(itemNameFromID), 'or')}.`;
}

return {
Expand Down Expand Up @@ -418,3 +418,21 @@ export function anyoneDiedInTOARaid(data: TOAOptions) {
export type JsonKeys<T> = {
[K in keyof T]: T[K] extends Prisma.JsonValue ? K : never;
}[keyof T];

export function replaceLast(str: string, pattern: string, replacement: string) {
const last = str.lastIndexOf(pattern);
return last !== -1 ? `${str.slice(0, last)}${replacement}${str.slice(last + pattern.length)}` : str;
}

export function joinStrings(itemList: any[], end?: string) {
DayV-git marked this conversation as resolved.
Show resolved Hide resolved
if (itemList.length < 2) return itemList.join(', ');
if (
itemList.reverse()[0] &&
(typeof itemList.reverse()[0] !== 'string' || !itemList.reverse()[0].toString().includes(','))
) {
return replaceLast(itemList.join(', '), ',', ` ${end ? end : 'and'}`);
} else {
// commas in last term will put str in weird place
return itemList.join(', ');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export async function claimAchievementDiaryCommand(user: MUser, diaryName: strin
return `You successfully completed the ${name} and received ${loot}.`;
}

return `You can't claim the ${name} because: \n -${reason}.`;
return `You can't claim the ${name} because: \n- ${reason}.`;
}

return `You have already completed the entire ${diary.name} diary!`;
Expand Down