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

Feat/generate adv stats first release fixes #75

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,37 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

## [v1.0.1] - 18/07/2024

- Upgrade to schema version v4.0.0
- DNA is now a serialized object
- DNA is not unique anymore

## [v0.7.9] - 24/04/2024

- Add new eggs and nefties for the Citrine version of Seekers of Tokane

## [v0.7.3] - 16/01/2024

- Wassie added to Quantum eggs

## [v0.7.0] - 06/12/2023

- Introduce Cybertooth and Wassie
- Add Fen and Moss eggs
- Update configuration format for adventure stats

## [v0.6.0] - 18/09/2023

- Introduce grade for DNA generation
- Add standard egg support in EggFactory

## [v0.5.4] - 19/09/2023

- Sync dictionary with ability names and descriptions from unity team

## [v0.5.1] - 10/08/2023

- Adjust Chocomint stats

## [v0.5.0] - 03/08/2023
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const parsed = df.parse(dna);
console.log(parsed);
```

> See `Parse` interface for more details on [df.parse](./ts/src/interfaces/types.ts)'s output.
> See `ParseV2` interface for more details on [df.parse](./ts/src/interfaces/types.ts)'s output.

### Get all eggs

Expand Down
4 changes: 3 additions & 1 deletion ts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@aurory/dnajs",
"version": "0.7.11",
"version": "1.0.1",
"repository": {
"type": "git",
"url": "git+https://github.com/Aurory-Game/dna.git"
Expand All @@ -12,6 +12,7 @@
"sp": "ts-node $1",
"test": "ts-mocha -p ./tsconfig.json -t 2500000 --exit tests/**/*.spec.ts",
"test:dna": "ts-mocha -p ./tsconfig.json -t 2500000 --exit tests/dna.spec.ts",
"test:dna2": "ts-mocha -p ./tsconfig.json -t 2500000 --exit tests/dna.v2.spec.ts",
"test:distribution": "ts-mocha -p ./tsconfig.json -t 2500000 --exit tests/distribution.spec.ts",
"build": "tsc -p tsconfig.build.json && cp -r src/deps lib/",
"prepare": "cd .. && husky install && cd ts && yarn build",
Expand Down Expand Up @@ -55,6 +56,7 @@
"camel-case": "^4.1.2",
"dotenv": "^16.3.1",
"google-spreadsheet": "^3.3.0",
"lz-string": "^1.5.0",
"randombytes": "^2.1.0",
"snake-case": "^3.0.4"
}
Expand Down
123 changes: 2 additions & 121 deletions ts/src/adventure_stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,103 +7,9 @@ import {
AdvStatsJSON,
ParseDataPerc,
AdvStatsJSONValue,
NeftyCodeName,
} from './interfaces/types';

/**
* Allow to pick a random number from an array, but in a deterministic way.
* The same input array will produce the same output number.
*/
function deterministicRandomPicker(arr: number[]): number {
const deterministicRandoms = arr.map((value, index, array) => {
const prevIndex = index === 0 ? array.length - 1 : index - 1;
const nextIndex = index === array.length - 1 ? 0 : index + 1;
return (array[prevIndex] + array[nextIndex] + value) % array.length;
});
arr.sort((a, b) => {
const indexA = arr.indexOf(a);
const indexB = arr.indexOf(b);
return deterministicRandoms[indexA] - deterministicRandoms[indexB];
});
return arr[0];
}

function removeGlitched(targetAverage: number, adventuresStatsOriginal: number[]): number[] {
const adventuresStats = [...adventuresStatsOriginal];
const maxNum = Math.max(...adventuresStats);
const maxIndex = adventuresStats.indexOf(maxNum);
adventuresStats[maxIndex] = 6;

while (floorAverage(adventuresStats) !== targetAverage) {
const validIndices = adventuresStats.reduce((indices, stat, index) => {
if (stat !== 0 && index !== maxIndex) {
indices.push(index);
}
return indices;
}, [] as number[]);

const indexToModify = deterministicRandomPicker(validIndices);
adventuresStats[indexToModify] -= 1;
}

return adventuresStats;
}

function makeGlitched(targetAverage: number, adventuresStatsOriginal: number[]): number[] {
const adventuresStats = adventuresStatsOriginal.map((num) => (num > 5 ? 5 : num));

while (floorAverage(adventuresStats) !== targetAverage) {
const validIndices = adventuresStats.reduce((indices, stat, index) => {
if (stat !== 5) {
indices.push(index);
}
return indices;
}, [] as number[]);

const indexToModify = deterministicRandomPicker(validIndices);
adventuresStats[indexToModify] += 1;
}

return adventuresStats;
}

function makeSchimmering(targetAverage: number, adventuresStatsOriginal: number[]): number[] {
const adventuresStats = adventuresStatsOriginal.map((num) => (num < 95 ? 95 : num));
while (floorAverage(adventuresStats) !== targetAverage) {
const validIndices = adventuresStats.reduce((indices, stat, index) => {
if (stat !== 95) {
indices.push(index);
}
return indices;
}, [] as number[]);

const indexToModify = deterministicRandomPicker(validIndices);
adventuresStats[indexToModify] -= 1;
}

return adventuresStats;
}

function removeSchimmering(targetAverage: number, adventuresStatsOriginal: number[]): number[] {
const adventuresStats = [...adventuresStatsOriginal];
const min = Math.min(...adventuresStats);
const minIndex = adventuresStats.indexOf(min);
adventuresStats[minIndex] = 94;

while (floorAverage(adventuresStats) !== targetAverage) {
const validIndices = adventuresStats.reduce((indices, stat, index) => {
if (stat !== 100 && index !== minIndex) {
indices.push(index);
}
return indices;
}, [] as number[]);

const indexToModify = deterministicRandomPicker(validIndices);
adventuresStats[indexToModify] += 1;
}

return adventuresStats;
}

function floorAverage(stats: number[]): number {
return Math.floor(stats.reduce((sum, stat) => sum + Math.round(stat), 0) / stats.length);
}
Expand Down Expand Up @@ -144,38 +50,13 @@ function convertStats(tacticsStats: ParseDataRangeCompleteness): ParseDataPerc {
return advArrToObj(adventuresStats);
}

function fixGlitchedSchimmering(
tacticsStatsObj: ParseDataRangeCompleteness,
adventuresStatsObj: ParseDataPerc
): ParseDataPerc {
const tacticsStats = tacticsStatsObjToArr(tacticsStatsObj);
const floorAvgGame1 = floorAverage(tacticsStats);
const adventuresStats = Object.values(adventuresStatsObj);
const isGlitched1 = tacticsStats.every((stat) => stat <= 5);
const isSchimmering1 = tacticsStats.every((stat) => stat >= 95);
const isGlitched2 = adventuresStats.every((stat) => stat <= 5);
const isSchimmering2 = adventuresStats.every((stat) => stat >= 95);

let adventuresStatsCorrected;
if (isGlitched1 === isGlitched2 && isSchimmering1 === isSchimmering2) {
return adventuresStatsObj;
} else if (isGlitched1 !== isGlitched2) {
if (isGlitched1) {
adventuresStatsCorrected = makeGlitched(floorAvgGame1, adventuresStats);
}
adventuresStatsCorrected = removeGlitched(floorAvgGame1, adventuresStats);
} else if (isSchimmering1) adventuresStatsCorrected = makeSchimmering(floorAvgGame1, adventuresStats);
else adventuresStatsCorrected = removeSchimmering(floorAvgGame1, adventuresStats);
return advArrToObj(adventuresStatsCorrected);
}

export function getAdventuresStats(dnaSchemaReader: DNASchemaReader, adventuresStats: AdvStatsJSON): ParseDataAdv {
const tacticsStats: Partial<ParseDataRangeCompleteness> = {};
dnaSchemaReader.getCompletenessGenes().forEach((gene: GeneWithValues) => {
tacticsStats[gene.name as keyof ParseDataRangeCompleteness] = Math.round((gene.completeness as number) * 100);
});
const fixedStats = convertStats(tacticsStats as ParseDataRangeCompleteness);
const neftieName = TACTICS_ADV_NAMES_MAP[dnaSchemaReader.archetype.fixed_attributes.name];
const neftieName = TACTICS_ADV_NAMES_MAP[dnaSchemaReader.archetype.fixed_attributes.name as NeftyCodeName];
const advStatsRanges = adventuresStats.nefties[neftieName];
Object.keys(fixedStats).forEach((key) => {
const min = advStatsRanges[`${key}Min` as keyof AdvStatsJSONValue];
Expand Down
10 changes: 8 additions & 2 deletions ts/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export const GLITCHED_PERIOD = 1500;
export const GLITCHED_RANGE_START = 5;
export const SCHIMMERING_RANGE_START = 95;

export const TACTICS_ADV_NAMES_MAP: Record<string, string> = {
export const TACTICS_ADV_NAMES_MAP = {
Nefty_Bitebit: 'id_bitebit',
Nefty_Dipking: 'id_dipking',
Nefty_Dinobit: 'id_dinobit',
Expand All @@ -29,4 +29,10 @@ export const TACTICS_ADV_NAMES_MAP: Record<string, string> = {
Nefty_Whiskube: 'id_whiskube',
Nefty_Walpuff: 'id_walpuff',
Nefty_Dinotusk: 'id_dinotusk',
};
} as const;

export const VERSION_LENGTH = 4;
export const LAST_SUPPORTED_VERSION_BY_V1 = '3.2.0';

// hp, atk, def, speed
export const N_STATS_SOT = 4;
4 changes: 2 additions & 2 deletions ts/src/deps/nefties_info.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
"Bitebit": "Bitebit may look cuddly, but don't be fooled by its charm - those aren't paper hands... they're DIAMOND CLAWS!",
"Dipking": "Dipking is bursting with personality and magical power, but handle with care - all that pent up energy may have EXPLOSIVE results!",
"Dinobit": "Dinobit is big, strong and tough, but careful of that temper - Make it mad and watch out for a charge that can PLOW THROUGH EVERYTHING in its path!",
"Shiba": "Shiba Ignite is always ready to jump into the heat of battle, but while it may not be the fastest - a helping paw is always there to DEFEND ITS ALLIES.",
"ShibaIgnite": "Shiba Ignite is always ready to jump into the heat of battle, but while it may not be the fastest - a helping paw is always there to DEFEND ITS ALLIES.",
"Zzoo": "Zzoo has a big beak and a bad attitude, but if it's on your side, both can be an asset - SWIFT STRIKES make its mean streak your advantage!",
"Blockchoy": "Block Choy may look tasty, but its real gift is far more delicious - a menu of healing powers is standing by to RE-FUEL its allies.",
"BlockChoy": "Block Choy may look tasty, but its real gift is far more delicious - a menu of healing powers is standing by to RE-FUEL its allies.",
"Number9": "Number 9 is a solid choice despite appearances, but remember - it has to FLY THROUGH ENEMIES before it can attack them.",
"Axobubble": "Axobubble is a born defender, but its magic is sneaky - buffs, curses and other mischief are sure to bubble up to HELP THE TEAM.",
"Unika": "Unika is cool under pressure, but don't let its delicate appearance confuse you - it's ready with an ICE COLD STRIKE!",
Expand Down
56 changes: 56 additions & 0 deletions ts/src/deps/nefties_info_deprecated.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"code_to_displayName": {
"Nefty_Bitebit": "Bitebit",
"Nefty_Dipking": "Dipking",
"Nefty_Dinobit": "Dinobit",
"Nefty_ShibaIgnite": "Shiba Ignite",
"Nefty_Zzoo": "Zzoo",
"Nefty_Blockchoy": "Block Choy",
"Nefty_Number9": "Number 9",
"Nefty_Axobubble": "Axobubble",
"Nefty_Unika": "Unika",
"Nefty_Chocomint": "Chocomint",
"Nefty_Cybertooth": "Cybertooth",
"Nefty_Wassie": "Wassie",
"Nefty_Dracurve": "Dracurve",
"Nefty_Raccoin": "Raccoin",
"Nefty_Shibark": "Shibark",
"Nefty_Unikirin": "Unikirin",
"Nefty_Beeblock": "Beeblock",
"Nefty_Chocorex": "Chocorex",
"Nefty_Keybab": "Keybab",
"Nefty_Bloomtail": "Bloomtail",
"Nefty_Tokoma": "Tokoma",
"Nefty_Ghouliath": "Ghouliath",
"Nefty_Whiskube": "Whiskube",
"Nefty_Walpuff": "Walpuff",
"Nefty_Dinotusk": "Dinotusk"
},
"family_to_description": {
"Bitebit": "Bitebit may look cuddly, but don't be fooled by its charm - those aren't paper hands... they're DIAMOND CLAWS!",
"Dipking": "Dipking is bursting with personality and magical power, but handle with care - all that pent up energy may have EXPLOSIVE results!",
"Dinobit": "Dinobit is big, strong and tough, but careful of that temper - Make it mad and watch out for a charge that can PLOW THROUGH EVERYTHING in its path!",
"Shiba": "Shiba Ignite is always ready to jump into the heat of battle, but while it may not be the fastest - a helping paw is always there to DEFEND ITS ALLIES.",
"Zzoo": "Zzoo has a big beak and a bad attitude, but if it's on your side, both can be an asset - SWIFT STRIKES make its mean streak your advantage!",
"Blockchoy": "Block Choy may look tasty, but its real gift is far more delicious - a menu of healing powers is standing by to RE-FUEL its allies.",
"Number9": "Number 9 is a solid choice despite appearances, but remember - it has to FLY THROUGH ENEMIES before it can attack them.",
"Axobubble": "Axobubble is a born defender, but its magic is sneaky - buffs, curses and other mischief are sure to bubble up to HELP THE TEAM.",
"Unika": "Unika is cool under pressure, but don't let its delicate appearance confuse you - it's ready with an ICE COLD STRIKE!",
"Chocomint": "Chocomints are born with a remnant of their shells on their heads. To pass into adulthood, a joust between two young Chocomints takes place. The victor is the one who cracks its shell to unveil its cherry.",
"Cybertooth": "Cybertooth uses its thick hide to fortify its defenses, skillfully weakening foes with its abilities to gain an advantage and deal significant damage.",
"Wassie": "Wassie is a nimble Neftie known for harnessing its abilities to enhance its speed and inflict substantial damage.",
"Dracurve": "Dracurve dictates the course of battle with shifts in stats and status effects. Exercise caution, for a few strategic choices can swiftly pave the way to devastation.",
"Raccoin": "Raccoin's a sly, laid-back Neftie, known for its nimbleness and love for naps.",
"Shibark": "Shibark is known to roam vast landscapes, unearthing treasures and marking its territory with resounding howls.",
"Unikirin": "Each step Unikirin takes resonates with the crackle of electric energy, a testament to its wild and untamed spirit.",
"Beeblock": "Beeblock, known for its calm nature, is tamed for its production of a deliciously sweet jelly named Nury. But when threatened, it delivers powerful stings, warding off any attacker.",
"Chocorex": "Praised for its loyalty, Chocorex stands as a favored companion and trusted mount within Tokane. However, due to its limited intelligence, it requires skilled riders.",
"Keybab": "When activating its self-defense mechanism, Keybab changes color to boiling red, and its spicy vapor makes anyone who inhales it shed tears.",
"Bloomtail": "Bloomtail is a spirited Neftie fueled by the flower adorning its back. It is said that the flower occasionally affects its movements, adding an intriguing twist to its nature!",
"Tokoma": "Tokomas, the most loyal among Nefties, forms a lifelong bond and will protect its trainer at all costs!",
"Ghouliath": "Ghouliaths were mighty dragons once, but they now linger as ghosts until their unresolved matters are dealt with...",
"Whiskube": "Whiskubes love to rest on ice, but their reflective bodies cause them to melt it while sleeping. This leads to a sudden plunge into cold water, giving them quite the wake-up call!",
"Walpuff": "Walpuffs are known for their soft heads but sturdy bodies. That's why they wear protective headgear adorned with razor-sharp tusks, providing formidable armor!",
"Dinotusk": "Dinotusks use their unique tails to ground themselves to Tokane, generating energy and enabling survival in harsh environments."
}
}
44 changes: 44 additions & 0 deletions ts/src/deps/schemas/aurory_dna_v4.0.0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"version": "4.0.0",
"version_date": "18/07/2024",
"global_genes_header": [
{
"name": "version",
"base": 2
}
],
"archetypes": {
"1": "Nefty_Bitebit",
"2": "Nefty_Dipking",
"3": "Nefty_Dinobit",
"4": "Nefty_ShibaIgnite",
"5": "Nefty_Zzoo",
"6": "Nefty_Blockchoy",
"7": "Nefty_Number9",
"8": "Nefty_Axobubble",
"9": "Nefty_Unika",
"10": "Nefty_Chocomint",
"11": "Nefty_Cybertooth",
"12": "Nefty_Wassie",
"13": "Nefty_Dracurve",
"14": "Nefty_Raccoin",
"15": "Nefty_Shibark",
"16": "Nefty_Unikirin",
"17": "Nefty_Beeblock",
"18": "Nefty_Chocorex",
"19": "Nefty_Keybab",
"20": "Nefty_Bloomtail",
"21": "Nefty_Tokoma",
"22": "Nefty_Ghouliath",
"23": "Nefty_Whiskube",
"24": "Nefty_Walpuff",
"25": "Nefty_Dinotusk"
},
"rarities": {
"0": "Common",
"1": "Uncommon",
"2": "Rare",
"3": "Epic",
"4": "Legendary"
}
}
2 changes: 1 addition & 1 deletion ts/src/deps/schemas/latest.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const LATEST_VERSION = '3.2.0';
export const LATEST_VERSION = '4.0.0';
Loading