Skip to content
This repository was archived by the owner on Aug 15, 2022. It is now read-only.

Commit 8c21582

Browse files
authored
feat: added fov & fovconvert commands and fov helper functions (#133)
* feat: added fov command and fov helper functions * feat: added fovconvert command and associated helper functions * docs: added relevant documentation for fovconvert command
1 parent a72b928 commit 8c21582

10 files changed

Lines changed: 188 additions & 20 deletions

File tree

docs/CNAME

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/commands/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Below is a shortlist of all the bot commands.
2525
| [`deg`](math.md#deg) | Converts Sensitivity to deg/mm |
2626
| [`mpi`](math.md#mpi) | Converts Sensitivity to MPI |
2727
| [`focal`](math.md#focal) | Focal Length Scales a desired sens between 2 fov values of the same type |
28-
| [`fov`](math.md#fov) | Finds the true vertical and horizontal FOVs for certain aspect ratio and game/FOV scaling method\(FILM notation\) |
28+
| [`fov`](math.md#fov) | Finds the true vertical and horizontal FoV that is being displayed on screen |
2929
| [`fovconvert`](math.md#fovconvert) | Converts a FOV value from one game or film notation to another |
3030
| [`inch`](math.md#inch) | Converts Sensitivity to inch/rev |
3131
| [`sens`](math.md#sens) | Converts cm/rev\|deg/mm\|MPI\|inch/rev\|arcmin to a game sensitivity default cm/rev |

docs/commands/math.md

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,31 @@ fps-focal <sens> <old fov> <new fov>
9898

9999
### fov
100100

101-
!!! error
102-
Command not implemented yet
101+
Finds the true vertical and horizontal FoV that is being displayed on screen
102+
103+
#### Usage
104+
105+
```text
106+
fps-fov <FoV> <game|FILM notation> <screen aspect ratio>
107+
```
108+
109+
#### Aliases
110+
111+
`fov-scaling`, `film`
103112

104113
### fovconvert
105114

106-
!!! error
107-
Command not implemented yet
115+
Converts a FoV value from one game or FILM notation to another.
116+
117+
#### Usage
118+
119+
```text
120+
fps-fovconvert <FoV> <input game|FILM notation> <output game|FILM notation> <screen aspect ratio>
121+
```
122+
123+
#### Aliases
124+
125+
`fov-convert`, `film-convert`, `convert-fov`
108126

109127
### inch
110128

docs/games.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: 'Supported Games'
2+
title: Supported Games
33
---
44

55
All the games that FPSMath supports and the features that are available for certain commands

src/arguments/aspect-ratio.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Argument, PieceContext, ArgumentContext } from '@sapphire/framework'
2+
3+
export default class GameArgument extends Argument<number> {
4+
public constructor(context: PieceContext) {
5+
super(context, { name: 'aspectRatio' })
6+
}
7+
8+
public run(parameter: string, context: ArgumentContext) {
9+
if (/\d{1,4}:\d{1,4}/.test(parameter)) {
10+
const split = parameter.split(':')
11+
return this.ok(Number(split[0]) / Number(split[1]))
12+
}
13+
return this.error({
14+
parameter,
15+
message: 'Not valid aspect ratio',
16+
identifier: 'aspectRatioNoSupport',
17+
context,
18+
})
19+
}
20+
}
21+
22+
declare module '@sapphire/framework' {
23+
interface ArgType {
24+
aspectRatio: number
25+
}
26+
}

src/arguments/film.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Argument, PieceContext, ArgumentContext } from '@sapphire/framework'
2+
import { getObject } from '../helpers/array'
23

34
export class UserArgument extends Argument<string> {
45
public constructor(context: PieceContext) {
@@ -7,11 +8,13 @@ export class UserArgument extends Argument<string> {
78

89
public run(parameter: string, context: ArgumentContext) {
910
if (
10-
/^hm[lfi]$|^vm[lfi]$|^\d{1,2}m[lfi]\d{1,2}$/i.test(
11-
parameter.toLowerCase()
11+
/^HM[LFI]$|^VM[LFI]$|^\d{1,2}M[LFI]\d{1,2}$/.test(
12+
parameter.toUpperCase()
1213
)
1314
) {
14-
return this.ok(parameter.toLowerCase())
15+
return this.ok(parameter.toUpperCase())
16+
} else if (getObject(parameter, 'film')) {
17+
return this.ok(getObject(parameter, 'film') as string)
1518
}
1619
return this.error({
1720
parameter,

src/commands/Math/fov.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { Command, CommandOptions } from '@sapphire/framework'
1+
import { Args, Command, CommandOptions } from '@sapphire/framework'
22
import type { Message } from 'discord.js'
33
import { ApplyOptions } from '@sapphire/decorators'
4+
import { filmToTrue } from '../../helpers/fovHelper'
45

56
@ApplyOptions<CommandOptions>({
67
aliases: ['fov-scaling', 'film'],
78
description:
8-
'Finds the true vertical and horizontal FOV that is being displayed on screen',
9+
'Finds the true vertical and horizontal FoV that is being displayed on screen',
910
detailedDescription: `
1011
📝 **| Command Usage**
1112
→ fps-fov *FoV* *GameName* *AspectRatio*
@@ -14,7 +15,7 @@ import { ApplyOptions } from '@sapphire/decorators'
1415
🖇️ **| Aliases**: \`fov-scaling\` and \`film\`
1516
1617
🔍 **| Extended Help**
17-
Finds the true vertical and horizontal FOV for certain aspect ratio that the game is being rendered at plus game's FoV scaling method
18+
Finds the true vertical or horizontal FoV for certain aspect ratio that the game is being rendered at plus game's FoV scaling method
1819
1920
⚙ **| Explained usage**
2021
→ **FoV**: The in-game FoV value or equivalent FoV value.
@@ -29,8 +30,16 @@ import { ApplyOptions } from '@sapphire/decorators'
2930
generateDashLessAliases: true,
3031
requiredClientPermissions: ['SEND_MESSAGES'],
3132
})
32-
export class UserCommand extends Command {
33-
public async run(message: Message) {
34-
return message.reply('Not fully implemented yet')
33+
export default class UserCommand extends Command {
34+
public async run(message: Message, args: Args) {
35+
const fov = await args.pick('float')
36+
const film = await args.pick('film')
37+
const aspect = await args.pick('aspectRatio')
38+
const { horizontalFOV, verticalFOV } = filmToTrue(fov, film, aspect)
39+
return message.reply(
40+
`Horizontal FoV: ${parseFloat(
41+
horizontalFOV.toFixed(5)
42+
)}°\nVertical FoV: ${parseFloat(verticalFOV.toFixed(5))}°`
43+
)
3544
}
3645
}

src/commands/Math/fovConvert.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { Command, CommandOptions } from '@sapphire/framework'
1+
import { Args, Command, CommandOptions } from '@sapphire/framework'
22
import type { Message } from 'discord.js'
33
import { ApplyOptions } from '@sapphire/decorators'
4+
import { filmToFilm } from '../../helpers/fovHelper'
45

56
@ApplyOptions<CommandOptions>({
67
aliases: ['fov-convert', 'film-convert', 'convert-fov'],
@@ -32,7 +33,12 @@ import { ApplyOptions } from '@sapphire/decorators'
3233
requiredClientPermissions: ['SEND_MESSAGES'],
3334
})
3435
export class UserCommand extends Command {
35-
public async run(message: Message) {
36-
return message.reply('Not fully implemented yet')
36+
public async run(message: Message, args: Args) {
37+
const fov = await args.pick('float')
38+
const inFILM = await args.pick('film')
39+
const outFILM = await args.pick('film')
40+
const aspect = await args.pick('aspectRatio')
41+
const output = filmToFilm(fov, inFILM, outFILM, aspect)
42+
return message.reply(`${parseFloat(output.toFixed(5))}°`)
3743
}
3844
}

src/helpers/array.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const array: {
3636
aliases: ['apex-legends', 'apex'],
3737
film: '4ML3',
3838
},
39-
Valorant: { yaw: 0.07, aliases: ['valorant', 'val'] },
39+
Valorant: { yaw: 0.07, aliases: ['valorant', 'val'], film: '16MS9' },
4040
Overwatch: {
4141
yaw: 0.0066,
4242
aliases: ['overwatch', 'ow'],

src/helpers/fovHelper.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
export function convertFOV(
2+
fov: number,
3+
inputAspect: number,
4+
outputAspect: number
5+
) {
6+
return (
7+
(Math.atan(
8+
(outputAspect / inputAspect) * Math.tan((fov * Math.PI) / 360)
9+
) *
10+
360) /
11+
Math.PI
12+
)
13+
}
14+
15+
export function filmToAspect(filmNotation: string) {
16+
const startString = filmNotation.split(/M/)[0]
17+
const endString = filmNotation.split(/M[FLI]/)[1]
18+
return Number(startString) / Number(endString)
19+
}
20+
21+
export function filmToTrue(
22+
fov: number,
23+
film: string,
24+
aspectRatio: number
25+
): fovValues {
26+
const filmAspect = filmToAspect(film)
27+
if (/^\d{1,2}MS\d{1,2}$/.test(film)) {
28+
return {
29+
horizontalFOV: fov,
30+
verticalFOV: convertFOV(fov, filmAspect, 1),
31+
}
32+
} else if (film.startsWith('H')) {
33+
return lockHorizontal(fov, aspectRatio)
34+
} else if (film.startsWith('V')) {
35+
return lockVertical(fov, aspectRatio)
36+
} else if (/^\d{1,2}ML\d{1,2}$/.test(film)) {
37+
return lockVertical(fov, aspectRatio, filmAspect)
38+
} else if (/^\d{1,2}MF\d{1,2}$/.test(film)) {
39+
if (aspectRatio > filmAspect) {
40+
return lockHorizontal(fov, aspectRatio)
41+
}
42+
return lockVertical(fov, aspectRatio, filmAspect)
43+
} else if (/^\d{1,2}MI\d{1,2}$/.test(film)) {
44+
if (aspectRatio < filmAspect) {
45+
return lockHorizontal(fov, aspectRatio)
46+
}
47+
return lockVertical(fov, aspectRatio, filmAspect)
48+
}
49+
throw Error('parsing failed')
50+
}
51+
52+
export function trueToFILM(
53+
{ horizontalFOV, verticalFOV }: fovValues,
54+
film: string,
55+
aspectRatio: number
56+
): number {
57+
const filmAspect = filmToAspect(film)
58+
if (/^\d{1,2}MS\d{1,2}$/.test(film) || film.startsWith('H')) {
59+
return horizontalFOV
60+
} else if (film.startsWith('V')) {
61+
return verticalFOV
62+
} else {
63+
return convertFOV(horizontalFOV, filmAspect, aspectRatio)
64+
}
65+
}
66+
67+
export function lockVertical(
68+
fov: number,
69+
aspectRatio: number,
70+
filmAspect?: number
71+
): fovValues {
72+
if (filmAspect) {
73+
return {
74+
horizontalFOV: convertFOV(fov, filmAspect, aspectRatio),
75+
verticalFOV: convertFOV(fov, filmAspect, 1),
76+
}
77+
}
78+
return {
79+
horizontalFOV: convertFOV(fov, 1, aspectRatio),
80+
verticalFOV: fov,
81+
}
82+
}
83+
84+
export function lockHorizontal(fov: number, aspectRatio: number): fovValues {
85+
return {
86+
horizontalFOV: fov,
87+
verticalFOV: convertFOV(fov, aspectRatio, 1),
88+
}
89+
}
90+
91+
export interface fovValues {
92+
horizontalFOV: number
93+
verticalFOV: number
94+
}
95+
96+
export function filmToFilm(
97+
fov: number,
98+
inFILM: string,
99+
outFILM: string,
100+
aspectRatio: number
101+
): number {
102+
return trueToFILM(
103+
filmToTrue(fov, inFILM, aspectRatio),
104+
outFILM,
105+
aspectRatio
106+
)
107+
}

0 commit comments

Comments
 (0)