Sometimes I fantasize of making games, and usually those games have loot of some sort. And IMO ARPG's are the kings of loot. The randomness and wide variety of items, creating endless possibilities, why make something more shallow? The ARPG I have most experience with is POE1, so the mods and methods I'll be using will closely resemble systems from game. I won't lie, I'm completely out of my element when it comes to this stuff. I have no idea how game companies create optimized and scalable systems. Still, we'll never figure anything out if we don't try, right?
I want to actually be able see stuff on the screen and have some user interaction instead of just logging stuff in a console. Frontend: Vue, Vite Backend: Express DB: Mongo I'll be using TypeScript for everything since I want to learn it, plus it's just better.
We're going to have a lot of data. There's so many items and base types and mods in POE. There's no way I can match that, so we'll just make a few items and a few mods at first and get those working before adding more. Here's what a base mod might look like. I plan on deriving higher tier mods using info from the base:
'addedWeaponPhysicalDamage1': {
type: 'addedPhysFlat',
weights: [
{ name: 'weapon_physical', weight: 1000, max_tier: N },
{ name: 'ring', weight: 250, max_tier: N-4 }
],
stats: [
{
name: 'minimum_weapon_physical_damage',
type: 'flat',
min: 5,
max: 7
},
{
name: 'maximum_weapon_physical_damage',
type: 'flat',
min: 10,
max: 14
},
],
required_level: 1,
breakpoint_index: 0
},I haven't added any types yet because I'm not positive of what the mods should look like yet. And here's some item meta data, and I'm just now realizing the tags should reference an array instead of being hard typed, since all higher level base types of a given item class will have the same exact tags I think, so I'll have to change that later.
export const items: ItemMeta[] = [
{
name: "Cutlass",
item_class: 'sword_1h',
weight: 1000,
tags: ['sword', 'weapon', 'weapon_1h', '1h', 'weapon_physical'],
drop_level: 1
},
{
name: "Twig",
item_class: 'wand',
weight: 800,
tags: ['wand', 'weapon', 'weapon_1h', '1h', 'weapon_magic'],
drop_level: 1
},
{
name: "Thorn Circlet",
weight: 500,
item_class: 'helm_int',
tags: ['helm', 'armor', 'armor_int', 'helm_int'],
drop_level: 1
},
{
name: "Ruby Ring",
weight: 200,
item_class: 'ring',
tags: ['ring'],
drop_level: 1
},
];I'm not sure of any of this stuff, so everything is subject to change, but here's what I'm thinking for handling stats right now. There's 3 main stat modifiers in POE, flat, increased/reduced, more/less. There's plenty of others like conversions and Mind over Matter, but I'm just going to focus on the main ones for now. Here's a class that represents a single stat. It keeps track of the base, flat, increased, and more, and calculates the total.
export class StatMod {
base: number = 0;
totalFlat: number = 0;
totalIncreased: number = 0;
totalMore: number = 1;
name: AllStats;
constructor(base: number, name: AllStats){
this.base = base;
this.name = name;
}
add(amount: number, type: MathType){
if(type === 'flat')
this.totalFlat += amount;
else if(type === 'increased')
this.totalIncreased += amount;
else if(type === 'more')
this.totalMore *= (1 + amount / 100);
return this.recalculate();
}
remove(amount: number, type: MathType){
if(type === 'flat')
this.totalFlat -= amount;
else if(type === 'increased')
this.totalIncreased -= amount;
else if(type === 'more')
this.totalMore *= (1 - amount / 100);
return this.recalculate();
}
recalculate(){
return (this.base + this.totalFlat) * (1 + this.totalIncreased / 100) * (this.totalMore);
}
}Will this work? I have no idea. Now let's make a class that manages the stats and puts them all in a map. We'll also keep an output map of just the stat and its value.
export class StatsManager {
stats = new Map<AllStats, StatMod>();
output: Partial<Record<AllStats, number>> = {};
newStat({ name, base }: { name: AllStats, base: number }){
this.stats.set(name, new StatMod(base, name));
}
increaseStat({ name, amount, type }: { name: AllStats, amount: number, type: MathType }){
let stat = this.check(name).add(amount, type);
this.output[name] = stat;
}
decreaseStat({ name, amount, type }: { name: AllStats, amount: number, type: MathType }){
let stat = this.check(name).remove(amount, type);
this.output[name] = stat;
}
updateOutput(){
for(let [key, val] of this.stats){
this.output[key] = val.recalculate();
}
}
private check(name: AllStats): StatMod {
const stat = this.stats.get(name);
if(!stat) throw new Error('stat dont exist');
return stat;
}
}Now we can create and modify stats and have them all in one place.
That's all for now. We setup some item and mod data, and created some classes to create, modify, and calculate any stats we want. Next, I want to make the logic to create all the mod tiers using the base mod. Until then.