Files
Hommie_RPG_Game/js/game/JobSystem.js
Maxim Dolgolyov fb5f09212b Initial commit: 3D Hommie RPG game
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 01:04:09 +03:00

189 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export class JobSystem {
constructor(game) {
this.game = game;
this.jobs = [];
this.activeJob = null;
this.jobTimer = 0;
this.completedToday = 0;
this.lastDay = 0;
}
init() {
this.generateJobs();
}
generateJobs() {
const allJobs = [
{ id: 'wash_car', name: 'Помыть машину', pay: 40, duration: 15, desc: 'Помыть машину на парковке', location: 'parking', skill: 'trading' },
{ id: 'unload', name: 'Разгрузить товар', pay: 80, duration: 25, desc: 'Разгрузить товар у магазина', location: 'shop', skill: 'survival' },
{ id: 'flyers', name: 'Раздать листовки', pay: 30, duration: 12, desc: 'Раздавать листовки на дороге', location: 'road', skill: 'begging' },
{ id: 'sweep', name: 'Подмести двор', pay: 25, duration: 10, desc: 'Навести порядок у церкви', location: 'church', skill: 'survival' },
{ id: 'help_granny', name: 'Помочь с сумками', pay: 35, duration: 15, desc: 'Донести сумки в парк', location: 'park', skill: 'survival' },
{ id: 'collect_trash', name: 'Собрать мусор', pay: 20, duration: 8, desc: 'Собрать мусор в парке', location: 'park', skill: 'scavenging' },
{ id: 'guard_stuff', name: 'Посторожить багаж', pay: 45, duration: 20, desc: 'Посторожить вещи на остановке', location: 'busstop', skill: 'survival' },
];
// Выбираем 3 случайных
const shuffled = allJobs.sort(() => Math.random() - 0.5);
this.jobs = shuffled.slice(0, 3).map(j => ({ ...j, available: true }));
}
getLocationPosition(loc) {
const positions = {
parking: { x: 40, z: -55 },
shop: { x: 20, z: -20 },
road: { x: 0, z: 0 },
church: { x: 70, z: 50 },
park: { x: -30, z: 40 },
busstop: { x: -38, z: -10 },
};
return positions[loc] || { x: 0, z: 0 };
}
getLocationName(loc) {
const names = {
parking: 'парковке',
shop: 'магазину',
road: 'дороге',
church: 'церкви',
park: 'парку',
busstop: 'остановке',
};
return names[loc] || 'месту';
}
showJobBoard() {
if (this.activeJob) {
this.game.notify('Вы уже выполняете работу!');
return;
}
const availableJobs = this.jobs.filter(j => j.available);
if (availableJobs.length === 0) {
this.game.ui.showDialog('Доска объявлений', 'Сейчас нет доступных подработок. Загляните завтра.', [
'Ладно'
], () => this.game.ui.hideDialog());
return;
}
const payMod = this.game.reputation.getJobPayModifier();
const choices = availableJobs.map(j => {
const pay = Math.floor(j.pay * payMod);
return `${j.name}${pay}₽ (${j.desc})`;
});
choices.push('Уйти');
this.game.sound.playDialogOpen();
this.game.ui.showDialog('Доска объявлений', 'Доступные подработки:', choices, (index) => {
if (index < availableJobs.length) {
this.startJob(availableJobs[index]);
}
this.game.ui.hideDialog();
});
}
startJob(job) {
this.activeJob = { ...job };
this.jobTimer = 0;
this.activeJob.isWorking = false;
this.activeJob.targetPos = this.getLocationPosition(job.location);
const locName = this.getLocationName(job.location);
this.game.notify(`Работа принята: ${job.name}. Идите к ${locName}!`);
}
update(dt) {
// Обновляем список работ при новом дне
if (this.game.gameDay !== this.lastDay) {
this.lastDay = this.game.gameDay;
this.completedToday = 0;
this.generateJobs();
}
if (!this.activeJob) return;
const player = this.game.player;
const pos = this.activeJob.targetPos;
const dx = player.position.x - pos.x;
const dz = player.position.z - pos.z;
const dist = Math.sqrt(dx * dx + dz * dz);
if (dist < 10) {
if (!this.activeJob.isWorking) {
this.activeJob.isWorking = true;
this.game.notify('Вы на месте. Работаете... (оставайтесь рядом)');
}
this.jobTimer += dt;
const progress = Math.min(1, this.jobTimer / this.activeJob.duration);
this.game.ui.updateJobProgress(progress, this.activeJob.name);
if (this.jobTimer >= this.activeJob.duration) {
this.completeJob();
}
} else if (this.activeJob.isWorking) {
this.activeJob.isWorking = false;
this.game.notify('Вы ушли с рабочего места! Вернитесь!', 'bad');
}
}
completeJob() {
const payMod = this.game.reputation.getJobPayModifier();
const pay = Math.floor(this.activeJob.pay * payMod);
this.game.player.stats.money += pay;
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 8);
this.game.sound.playCoin();
this.game.reputation.change(3);
this.game.skills.addXP(this.activeJob.skill || 'survival', 3);
this.game.notify(`Работа выполнена! +${pay}₽, +8 Настроение`, 'good');
this.game.questSystem.onEvent('complete_job');
this.game.totalJobsCompleted++;
// Ачивки
this.game.achievements.check('first_job_done');
if (this.game.totalJobsCompleted >= 10) {
this.game.achievements.check('jobs_10');
}
const idx = this.jobs.findIndex(j => j.id === this.activeJob.id);
if (idx >= 0) this.jobs[idx].available = false;
this.activeJob = null;
this.jobTimer = 0;
this.completedToday++;
this.game.ui.hideJobProgress();
}
cancelJob() {
if (this.activeJob) {
this.game.notify('Работа отменена.', 'bad');
this.game.reputation.change(-2);
this.activeJob = null;
this.jobTimer = 0;
this.game.ui.hideJobProgress();
}
}
getSaveData() {
return {
completedToday: this.completedToday,
lastDay: this.lastDay
};
}
loadSaveData(data) {
if (data) {
this.completedToday = data.completedToday || 0;
this.lastDay = data.lastDay || 0;
}
}
reset() {
this.activeJob = null;
this.jobTimer = 0;
this.completedToday = 0;
this.lastDay = 0;
this.generateJobs();
}
}