feat: add poc
This commit is contained in:
parent
43d27b04d9
commit
4a4fa05ce4
53 changed files with 6191 additions and 0 deletions
176
src/systems/AbsorptionSystem.js
Normal file
176
src/systems/AbsorptionSystem.js
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
import { System } from '../core/System.js';
|
||||
import { GameConfig } from '../GameConfig.js';
|
||||
import { Events } from '../core/EventBus.js';
|
||||
|
||||
export class AbsorptionSystem extends System {
|
||||
constructor() {
|
||||
super('AbsorptionSystem');
|
||||
this.requiredComponents = ['Position', 'Absorbable'];
|
||||
this.priority = 25;
|
||||
this.absorptionEffects = []; // Visual effects
|
||||
}
|
||||
|
||||
process(deltaTime, _entities) {
|
||||
const playerController = this.engine.systems.find(s => s.name === 'PlayerControllerSystem');
|
||||
const player = playerController ? playerController.getPlayerEntity() : null;
|
||||
|
||||
if (!player) return;
|
||||
|
||||
const playerPos = player.getComponent('Position');
|
||||
const playerEvolution = player.getComponent('Evolution');
|
||||
const playerSkills = player.getComponent('Skills');
|
||||
const playerStats = player.getComponent('Stats');
|
||||
const skillProgress = player.getComponent('SkillProgress');
|
||||
|
||||
if (!playerPos || !playerEvolution) return;
|
||||
|
||||
// Get ALL entities (including inactive ones) for absorption check
|
||||
const allEntities = this.engine.entities; // Get raw entities array, not filtered
|
||||
|
||||
const config = GameConfig.Absorption;
|
||||
|
||||
// Check for absorbable entities near player
|
||||
allEntities.forEach(entity => {
|
||||
if (entity === player) return;
|
||||
// Allow inactive entities if they're dead and absorbable
|
||||
if (!entity.active) {
|
||||
const health = entity.getComponent('Health');
|
||||
const absorbable = entity.getComponent('Absorbable');
|
||||
// Only process inactive entities if they're dead and not yet absorbed
|
||||
if (!health || !health.isDead() || !absorbable || absorbable.absorbed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!entity.hasComponent('Absorbable')) return;
|
||||
if (!entity.hasComponent('Health')) return;
|
||||
|
||||
const absorbable = entity.getComponent('Absorbable');
|
||||
const health = entity.getComponent('Health');
|
||||
const entityPos = entity.getComponent('Position');
|
||||
|
||||
if (!entityPos) return;
|
||||
|
||||
// Check if creature is dead and in absorption range
|
||||
if (health.isDead() && !absorbable.absorbed) {
|
||||
const dx = playerPos.x - entityPos.x;
|
||||
const dy = playerPos.y - entityPos.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance <= config.range) {
|
||||
this.absorbEntity(player, entity, absorbable, playerEvolution, playerSkills, playerStats, skillProgress);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Update visual effects
|
||||
this.updateEffects(deltaTime);
|
||||
}
|
||||
|
||||
absorbEntity(player, entity, absorbable, evolution, skills, stats, skillProgress) {
|
||||
if (absorbable.absorbed) return;
|
||||
|
||||
absorbable.absorbed = true;
|
||||
const entityPos = entity.getComponent('Position');
|
||||
const health = player.getComponent('Health');
|
||||
const config = GameConfig.Absorption;
|
||||
|
||||
// Add evolution points
|
||||
evolution.addEvolution(
|
||||
absorbable.evolutionData.human,
|
||||
absorbable.evolutionData.beast,
|
||||
absorbable.evolutionData.slime
|
||||
);
|
||||
|
||||
// Track skill progress (need to absorb multiple times to learn)
|
||||
// Always track progress for ALL skills the enemy has, regardless of roll
|
||||
if (skillProgress && absorbable.skillsGranted && absorbable.skillsGranted.length > 0) {
|
||||
absorbable.skillsGranted.forEach(skill => {
|
||||
// Always add progress when absorbing an enemy with this skill
|
||||
const currentProgress = skillProgress.addSkillProgress(skill.id);
|
||||
const required = skillProgress.requiredAbsorptions;
|
||||
|
||||
// If we've absorbed enough, learn the skill
|
||||
if (currentProgress >= required && !skills.hasSkill(skill.id)) {
|
||||
skills.addSkill(skill.id, false);
|
||||
this.engine.emit(Events.SKILL_LEARNED, { id: skill.id });
|
||||
console.log(`Learned skill: ${skill.id}!`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Heal from absorption (slime recovers by consuming)
|
||||
if (health) {
|
||||
const healPercent = config.healPercentMin + Math.random() * (config.healPercentMax - config.healPercentMin);
|
||||
const healAmount = health.maxHp * healPercent;
|
||||
health.heal(healAmount);
|
||||
}
|
||||
|
||||
// Check for mutation
|
||||
if (absorbable.shouldMutate() && stats) {
|
||||
this.applyMutation(stats);
|
||||
evolution.checkMutations(stats, this.engine);
|
||||
}
|
||||
|
||||
// Visual effect
|
||||
if (entityPos) {
|
||||
this.addAbsorptionEffect(entityPos.x, entityPos.y);
|
||||
}
|
||||
|
||||
// Mark as absorbed - DeathSystem will handle removal after absorption window
|
||||
// Don't remove immediately, let DeathSystem handle it
|
||||
}
|
||||
|
||||
applyMutation(stats) {
|
||||
// Random stat mutation
|
||||
const mutations = [
|
||||
{ stat: 'strength', amount: 5 },
|
||||
{ stat: 'agility', amount: 5 },
|
||||
{ stat: 'intelligence', amount: 5 },
|
||||
{ stat: 'constitution', amount: 5 },
|
||||
{ stat: 'perception', amount: 5 },
|
||||
];
|
||||
|
||||
const mutation = mutations[Math.floor(Math.random() * mutations.length)];
|
||||
stats[mutation.stat] += mutation.amount;
|
||||
|
||||
// Could also add negative mutations
|
||||
if (Math.random() < 0.3) {
|
||||
const negativeStat = mutations[Math.floor(Math.random() * mutations.length)];
|
||||
stats[negativeStat.stat] = Math.max(1, stats[negativeStat.stat] - 2);
|
||||
}
|
||||
}
|
||||
|
||||
addAbsorptionEffect(x, y) {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
this.absorptionEffects.push({
|
||||
x,
|
||||
y,
|
||||
vx: (Math.random() - 0.5) * 200,
|
||||
vy: (Math.random() - 0.5) * 200,
|
||||
lifetime: 0.5 + Math.random() * 0.5,
|
||||
size: 3 + Math.random() * 5,
|
||||
color: `hsl(${120 + Math.random() * 60}, 100%, 50%)`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateEffects(deltaTime) {
|
||||
for (let i = this.absorptionEffects.length - 1; i >= 0; i--) {
|
||||
const effect = this.absorptionEffects[i];
|
||||
effect.x += effect.vx * deltaTime;
|
||||
effect.y += effect.vy * deltaTime;
|
||||
effect.lifetime -= deltaTime;
|
||||
effect.vx *= 0.95;
|
||||
effect.vy *= 0.95;
|
||||
|
||||
if (effect.lifetime <= 0) {
|
||||
this.absorptionEffects.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getEffects() {
|
||||
return this.absorptionEffects;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue