feat: add career engine with unlock, income, exp, level-up
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"careers": [
|
||||
{
|
||||
"id": "student",
|
||||
"name": "学童",
|
||||
"type": "scholar",
|
||||
"unlockConditions": {
|
||||
"type": "age",
|
||||
"op": ">=",
|
||||
"value": 6
|
||||
},
|
||||
"dailyIncome": 1,
|
||||
"expCurve": {
|
||||
"base": 10,
|
||||
"factor": 1.15
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "book_boy",
|
||||
"name": "书童",
|
||||
"type": "scholar",
|
||||
"unlockConditions": {
|
||||
"type": "careerLevel",
|
||||
"op": ">=",
|
||||
"careerId": "student",
|
||||
"value": 100
|
||||
},
|
||||
"dailyIncome": 2,
|
||||
"expCurve": {
|
||||
"base": 50,
|
||||
"factor": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "scholar",
|
||||
"name": "书生",
|
||||
"type": "scholar",
|
||||
"unlockConditions": {
|
||||
"type": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "careerLevel",
|
||||
"op": ">=",
|
||||
"careerId": "student",
|
||||
"value": 250
|
||||
},
|
||||
{
|
||||
"type": "age",
|
||||
"op": ">=",
|
||||
"value": 14
|
||||
}
|
||||
]
|
||||
},
|
||||
"dailyIncome": -3,
|
||||
"expCurve": {
|
||||
"base": 100,
|
||||
"factor": 1.25
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "soldier",
|
||||
"name": "士兵",
|
||||
"type": "military",
|
||||
"unlockConditions": {
|
||||
"type": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "age",
|
||||
"op": ">=",
|
||||
"value": 14
|
||||
},
|
||||
{
|
||||
"type": "stat",
|
||||
"op": ">=",
|
||||
"stat": "body",
|
||||
"value": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
"dailyIncome": 2,
|
||||
"expCurve": {
|
||||
"base": 20,
|
||||
"factor": 1.18
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "taoist_priest",
|
||||
"name": "道士",
|
||||
"type": "immortal",
|
||||
"unlockConditions": {
|
||||
"type": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "age",
|
||||
"op": ">=",
|
||||
"value": 10
|
||||
},
|
||||
{
|
||||
"type": "hasItem",
|
||||
"itemId": "taoist_license"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dailyIncome": 1,
|
||||
"expCurve": {
|
||||
"base": 30,
|
||||
"factor": 1.22
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { evaluateCondition } from './conditionEvaluator.js';
|
||||
|
||||
const STAT_MAP = {
|
||||
scholar: 'wisdom',
|
||||
military: 'body',
|
||||
jianghu: 'charm',
|
||||
political: 'intelligence',
|
||||
immortal: 'wisdom',
|
||||
business: 'business',
|
||||
};
|
||||
|
||||
let _config = null;
|
||||
|
||||
export function setCareerConfig(config) {
|
||||
_config = config;
|
||||
}
|
||||
|
||||
export function getCareerConfig() {
|
||||
return _config;
|
||||
}
|
||||
|
||||
export function checkUnlocks(config, state) {
|
||||
if (!state.careers) {
|
||||
state.careers = {};
|
||||
}
|
||||
for (const career of config.careers) {
|
||||
if (!state.careers[career.id]) {
|
||||
if (evaluateCondition(career.unlockConditions, state)) {
|
||||
state.careers[career.id] = { level: 0, exp: 0 };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function calcDailyIncome(config, state) {
|
||||
let total = 0;
|
||||
for (const career of config.careers) {
|
||||
if (state.careers?.[career.id]) {
|
||||
total += career.dailyIncome;
|
||||
}
|
||||
}
|
||||
const businessStat = state.stats?.business ?? 0;
|
||||
const bonus = 1 + Math.min(businessStat, 100) * 0.01;
|
||||
return total * bonus;
|
||||
}
|
||||
|
||||
export function calcDailyExp(config, state, careerId) {
|
||||
const careerCfg = config.careers.find(c => c.id === careerId);
|
||||
if (!careerCfg) return 0;
|
||||
const base = careerCfg.expCurve.base;
|
||||
const statKey = STAT_MAP[careerCfg.type];
|
||||
const stat = state.stats?.[statKey] ?? 0;
|
||||
const statBonus = 1 + Math.min(stat, 100) * 0.01;
|
||||
const meta = state.metaExp?.[careerId] || 0;
|
||||
const metaBonus = 1 + Math.log(1 + meta / 100);
|
||||
return base * statBonus * metaBonus;
|
||||
}
|
||||
|
||||
export function checkLevelUp(config, state) {
|
||||
if (!state.careers) return;
|
||||
for (const career of config.careers) {
|
||||
const careerState = state.careers[career.id];
|
||||
if (!careerState) continue;
|
||||
const { base, factor } = career.expCurve;
|
||||
let need = base * Math.pow(factor, careerState.level);
|
||||
while (careerState.exp >= need) {
|
||||
careerState.exp -= need;
|
||||
careerState.level++;
|
||||
need = base * Math.pow(factor, careerState.level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { STAT_MAP };
|
||||
Reference in New Issue
Block a user