Initial commit: 3D Hommie RPG game
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
230
js/game/Events.js
Normal file
230
js/game/Events.js
Normal file
@@ -0,0 +1,230 @@
|
||||
export class EventSystem {
|
||||
constructor(game) {
|
||||
this.game = game;
|
||||
this.timer = 30 + Math.random() * 60;
|
||||
this.eventCooldown = 0;
|
||||
this.activeEvent = null;
|
||||
}
|
||||
|
||||
update(dt) {
|
||||
if (this.eventCooldown > 0) {
|
||||
this.eventCooldown -= dt;
|
||||
return;
|
||||
}
|
||||
|
||||
this.timer -= dt;
|
||||
if (this.timer <= 0) {
|
||||
this.triggerRandom();
|
||||
this.timer = 40 + Math.random() * 80;
|
||||
}
|
||||
}
|
||||
|
||||
triggerRandom() {
|
||||
const hour = this.game.gameTime / 60;
|
||||
const isNight = hour < 6 || hour > 21;
|
||||
const player = this.game.player;
|
||||
|
||||
const events = [
|
||||
{ weight: 10, fn: () => this.eventFoundWallet() },
|
||||
{ weight: 8, fn: () => this.eventStrayDogFood() },
|
||||
{ weight: 7, fn: () => this.eventOldFriend() },
|
||||
{ weight: 6, fn: () => this.eventRainOfCoins() },
|
||||
{ weight: 8, fn: () => this.eventKindStranger() },
|
||||
{ weight: 5, fn: () => this.eventFoodTruck() },
|
||||
{ weight: isNight ? 10 : 3, fn: () => this.eventColdWind() },
|
||||
{ weight: isNight ? 8 : 2, fn: () => this.eventScaryNoise() },
|
||||
{ weight: player.stats.mood < 30 ? 10 : 3, fn: () => this.eventMemory() },
|
||||
{ weight: 4, fn: () => this.eventStreetMusician() },
|
||||
{ weight: player.stats.health < 40 ? 8 : 2, fn: () => this.eventAmbulance() },
|
||||
{ weight: 5, fn: () => this.eventNewspaper() },
|
||||
{ weight: 6, fn: () => this.eventPigeons() },
|
||||
{ weight: isNight ? 2 : 6, fn: () => this.eventSunshine() },
|
||||
];
|
||||
|
||||
const totalWeight = events.reduce((s, e) => s + e.weight, 0);
|
||||
let roll = Math.random() * totalWeight;
|
||||
|
||||
for (const event of events) {
|
||||
roll -= event.weight;
|
||||
if (roll <= 0) {
|
||||
event.fn();
|
||||
this.eventCooldown = 20;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eventFoundWallet() {
|
||||
const amount = 20 + Math.floor(Math.random() * 80);
|
||||
this.game.ui.showDialog('Находка', `Вы нашли на земле кошелёк! Внутри ${amount}₽. Что делать?`, [
|
||||
`Забрать деньги (+${amount}₽)`,
|
||||
'Оставить на месте (может кто-то вернётся)',
|
||||
], (i) => {
|
||||
if (i === 0) {
|
||||
this.game.player.stats.money += amount;
|
||||
this.game.sound.playCoin();
|
||||
this.game.notify(`+${amount}₽`, 'good');
|
||||
this.game.player.stats.mood = Math.max(0, this.game.player.stats.mood - 2);
|
||||
this.game.reputation.change(-5);
|
||||
} else {
|
||||
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 8);
|
||||
this.game.notify('+8 Настроение. Вы поступили честно.', 'good');
|
||||
this.game.reputation.change(10);
|
||||
}
|
||||
this.game.ui.hideDialog();
|
||||
});
|
||||
}
|
||||
|
||||
eventStrayDogFood() {
|
||||
if (this.game.dog && this.game.dog.adopted) return;
|
||||
const hasBread = this.game.inventory.getCount('bread') > 0;
|
||||
const choices = hasBread
|
||||
? ['Покормить хлебом', 'Прогнать']
|
||||
: ['Погладить', 'Прогнать'];
|
||||
|
||||
this.game.ui.showDialog('Событие', 'Бездомный пёс подошёл к вам и смотрит голодными глазами...', choices, (i) => {
|
||||
if (i === 0) {
|
||||
if (hasBread) {
|
||||
this.game.inventory.removeItem('bread', 1);
|
||||
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 12);
|
||||
this.game.notify('Пёс виляет хвостом! +12 Настроение', 'good');
|
||||
// Приручить если ещё не приручен
|
||||
if (this.game.dog && !this.game.dog.adopted) {
|
||||
this.game.dog.adopt();
|
||||
this.game.notify('Пёс решил остаться с вами!', 'good');
|
||||
this.game.questSystem.onEvent('adopt_dog');
|
||||
}
|
||||
} else {
|
||||
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 5);
|
||||
this.game.notify('Пёс благодарно лизнул руку.', 'good');
|
||||
}
|
||||
} else {
|
||||
this.game.notify('Пёс убежал с поджатым хвостом...');
|
||||
this.game.player.stats.mood = Math.max(0, this.game.player.stats.mood - 3);
|
||||
}
|
||||
this.game.ui.hideDialog();
|
||||
});
|
||||
}
|
||||
|
||||
eventOldFriend() {
|
||||
this.game.ui.showDialog('Событие', 'Вы встретили старого знакомого. Он узнал вас и выглядит смущённым...', [
|
||||
'"Привет, давно не виделись..."',
|
||||
'Отвернуться',
|
||||
], (i) => {
|
||||
if (i === 0) {
|
||||
const roll = Math.random();
|
||||
if (roll < 0.5) {
|
||||
const amount = 50 + Math.floor(Math.random() * 100);
|
||||
this.game.player.stats.money += amount;
|
||||
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 10);
|
||||
this.game.sound.playCoin();
|
||||
this.game.notify(`Он дал вам ${amount}₽ и пожелал удачи.`, 'good');
|
||||
} else {
|
||||
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 5);
|
||||
this.game.notify('Он обнял вас и пожелал сил. +5 Настроение', 'good');
|
||||
}
|
||||
} else {
|
||||
this.game.player.stats.mood = Math.max(0, this.game.player.stats.mood - 5);
|
||||
this.game.notify('Вы отвернулись. Стало грустно.', 'bad');
|
||||
}
|
||||
this.game.ui.hideDialog();
|
||||
});
|
||||
}
|
||||
|
||||
eventRainOfCoins() {
|
||||
const amount = 5 + Math.floor(Math.random() * 15);
|
||||
this.game.player.stats.money += amount;
|
||||
this.game.sound.playCoin();
|
||||
this.game.notify(`Кто-то обронил мелочь! +${amount}₽`, 'good');
|
||||
}
|
||||
|
||||
eventKindStranger() {
|
||||
this.game.ui.showDialog('Событие', 'К вам подошёл человек в дорогом пальто. "Я из благотворительной организации. Хотите горячий обед?"', [
|
||||
'Да, спасибо!',
|
||||
'Нет, обойдусь',
|
||||
], (i) => {
|
||||
if (i === 0) {
|
||||
this.game.player.stats.hunger = Math.min(100, this.game.player.stats.hunger + 50);
|
||||
this.game.player.stats.warmth = Math.min(100, this.game.player.stats.warmth + 15);
|
||||
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 15);
|
||||
this.game.sound.playEat();
|
||||
this.game.notify('Вы сытно поели! +50 Сытость, +15 Тепло, +15 Настроение', 'good');
|
||||
}
|
||||
this.game.ui.hideDialog();
|
||||
});
|
||||
}
|
||||
|
||||
eventFoodTruck() {
|
||||
this.game.notify('Фудтрак раздаёт бесплатную еду рядом!');
|
||||
this.game.inventory.addItem('can', 1);
|
||||
this.game.inventory.addItem('tea', 1);
|
||||
this.game.sound.playPickup();
|
||||
this.game.notify('Получено: Консервы, Чай', 'good');
|
||||
}
|
||||
|
||||
eventColdWind() {
|
||||
this.game.player.stats.warmth = Math.max(0, this.game.player.stats.warmth - 15);
|
||||
this.game.player.stats.mood = Math.max(0, this.game.player.stats.mood - 5);
|
||||
this.game.notify('Порыв ледяного ветра! -15 Тепло', 'bad');
|
||||
}
|
||||
|
||||
eventScaryNoise() {
|
||||
this.game.player.stats.mood = Math.max(0, this.game.player.stats.mood - 8);
|
||||
this.game.notify('Странный шум в темноте... -8 Настроение', 'bad');
|
||||
this.game.sound.playHurt();
|
||||
}
|
||||
|
||||
eventMemory() {
|
||||
const memories = [
|
||||
'Вы вспомнили детство... тёплый дом, мамин суп...',
|
||||
'В голове всплыло лицо старого друга... Где он сейчас?',
|
||||
'Вы нашли в кармане старую фотографию. Сердце защемило.',
|
||||
'Знакомая мелодия из окна... Вы когда-то танцевали под неё.',
|
||||
];
|
||||
const text = memories[Math.floor(Math.random() * memories.length)];
|
||||
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 3);
|
||||
this.game.notify(text);
|
||||
}
|
||||
|
||||
eventStreetMusician() {
|
||||
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 10);
|
||||
this.game.notify('Уличный музыкант играет красивую мелодию. +10 Настроение', 'good');
|
||||
}
|
||||
|
||||
eventAmbulance() {
|
||||
this.game.ui.showDialog('Событие', 'Медработник-волонтёр заметил вас. "Давайте я вас осмотрю?"', [
|
||||
'Да, пожалуйста',
|
||||
'Не нужно',
|
||||
], (i) => {
|
||||
if (i === 0) {
|
||||
this.game.player.stats.health = Math.min(100, this.game.player.stats.health + 30);
|
||||
this.game.inventory.addItem('bandage', 1);
|
||||
this.game.notify('+30 Здоровье. Получен: Бинт', 'good');
|
||||
}
|
||||
this.game.ui.hideDialog();
|
||||
});
|
||||
}
|
||||
|
||||
eventNewspaper() {
|
||||
this.game.inventory.addItem('newspaper', 1);
|
||||
this.game.sound.playPickup();
|
||||
this.game.notify('Ветер принёс газету. Можно почитать.', 'good');
|
||||
}
|
||||
|
||||
eventPigeons() {
|
||||
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 3);
|
||||
this.game.notify('Стая голубей приземлилась рядом. Маленькая радость.');
|
||||
}
|
||||
|
||||
eventSunshine() {
|
||||
this.game.player.stats.warmth = Math.min(100, this.game.player.stats.warmth + 8);
|
||||
this.game.player.stats.mood = Math.min(100, this.game.player.stats.mood + 5);
|
||||
this.game.notify('Тёплый луч солнца согрел лицо. +8 Тепло', 'good');
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.timer = 30 + Math.random() * 60;
|
||||
this.eventCooldown = 0;
|
||||
this.activeEvent = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user