class Talent { constructor(system) { this.#system = system; } #system; #talents; #talentPullCount; #talentRate; #additions; initial({talents}) { this.#talents = talents; const emt = this.#system.function(this.#system.Function.CONDITION).extractMaxTriggers; for(const id in talents) { const talent = talents[id]; talent.id= Number(id); talent.grade = Number(talent.grade); talent.max_triggers = emt(talent.condition); if(talent.replacement) { for(let key in talent.replacement) { const obj = {}; for(let value of talent.replacement[key]) { value = `${value}`.split('*'); obj[value[0]||0] = Number(value[1]) || 1; } talent.replacement[key] = obj; } } } return this.count; } get count() { return Object.keys(this.#talents).length; } get #prop() { return this.#system.request(this.#system.Module.PROPERTY); } config({ talentPullCount = 10, // number of talents to pull from the talent pool talentRate = { 1:100, 2:10, 3:1, total: 1000 }, // rate of talent pull additions = {}, // additional additions } = {}) { this.#talentPullCount = talentPullCount; this.#talentRate = talentRate; this.#additions = additions; } check(talentId) { const { condition } = this.get(talentId); return this.#system.check(this.#prop, condition); } get(talentId) { const talent = this.#talents[talentId]; if(!talent) throw new Error(`[ERROR] No Talent[${talentId}]`); return this.#system.clone(talent); } information(talentId) { const { grade, name, description } = this.get(talentId) return { grade, name, description }; } exclude(talents, excludeId) { const { exclude } = this.get(excludeId); for(const talent of talents) { if(exclude) { for(const e of exclude) { if(talent == e) return talent; } } const excludeReverse = this.get(talent).exclude; if(excludeReverse) { for (const e of excludeReverse) { if (excludeId == e) return talent } } } return null; } getAddition(type, value) { if(!this.#additions[type]) return {}; for(const [min, addition] of this.#additions[type]) { if(value >= min) return addition; } return {}; } getRate(additionValues = {}) { const rate = this.#system.clone(this.#talentRate); const addition = { 1:1, 2:1, 3:1, }; Object.keys(additionValues).forEach(key => { const addi = this.getAddition(key, additionValues[key]) for(const grade in addi) addition[grade] += addi[grade]; }); for(const grade in addition) rate[grade] *= addition[grade]; return rate; } talentRandom(include, additionValues) { const rate = this.getRate(additionValues); const randomGrade = () => { let randomNumber = Math.floor(Math.random() * rate.total); if((randomNumber -= rate[3]) < 0) return 3; if((randomNumber -= rate[2]) < 0) return 2; if((randomNumber - rate[1]) < 0) return 1; return 0; } const talentList = {}; for(const talentId in this.#talents) { const { id, grade, name, description, exclusive } = this.#talents[talentId]; if(!!exclusive) continue; if(id == include) { include = { grade, name, description, id }; continue; } if(!talentList[grade]) talentList[grade] = [{ grade, name, description, id }]; else talentList[grade].push({ grade, name, description, id }); } return new Array(this.#talentPullCount) .fill(1).map((v, i)=>{ if(!i && include) return include; let grade = randomGrade(); while(talentList[grade].length == 0) grade--; const length = talentList[grade].length; const random = Math.floor(Math.random()*length) % length; return talentList[grade].splice(random,1)[0]; }); } random(count) { const talents = Object .keys(this.#talents) .filter(id=>!this.#talents[id].exclusive); return new Array(count) .fill(1) .map(()=>talents.splice( Math.floor(Math.random()*talents.length)%talents.length, 1 )[0] ); } allocationAddition(talents) { if(Array.isArray(talents)) { let addition = 0; for(const talent of talents) addition += this.allocationAddition(talent); return addition; } return Number(this.get(talents).status) || 0; } do(talentId) { const { effect, condition, grade, name, description } = this.get(talentId); if(condition && !this.#system.check(condition)) return null; return { effect, grade, name, description }; } replace(talents) { const getReplaceList = (talent, talents) => { const { replacement } = this.get(talent); if(!replacement) return null; const list = []; if(replacement.grade) { this.forEach(({id, grade, exclusive})=>{ if(exclusive) return; if(!replacement.grade[grade]) return; if(this.exclude(talents, id)) return; list.push([id, replacement.grade[grade]]); }) } if(replacement.talent) { for(let id in replacement.talent) { id = Number(id); if(this.exclude(talents, id)) continue; list.push([id, replacement.talent[id]]); } } return list; } const wr = this.#system.function(this.#system.Function.UTIL).weightRandom; const replace = (talent, talents) => { const replaceList = getReplaceList(talent, talents); if(!replaceList) return talent; const rand = wr(replaceList); return replace( rand, talents.concat(rand) ); } const newTalents = this.#system.clone(talents); const result = {}; for(const talent of talents) { const replaceId = replace(talent, newTalents); if(replaceId != talent) { result[talent] = replaceId; newTalents.push(replaceId); } } return result; } forEach(callback) { if(typeof callback != 'function') return; for(const id in this.#talents) callback(this.#system.clone(this.#talents[id]), id); } } export default Talent;