Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions srcs/core/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -850,8 +850,14 @@ void Engine::run() {
impl_->attack_sync_timer -= dt;
if (impl_->death_sync_timer > 0.0f)
impl_->death_sync_timer -= dt;
const bool is_mob_host = !impl_->multiplayer ||
impl_->net_client.playerId() == 1;
bool is_mob_host = !impl_->multiplayer;
if (!is_mob_host) {
const uint8_t my_id = impl_->net_client.playerId();
is_mob_host = true;
for (const auto& [id, rp] : impl_->net_client.remotePlayers()) {
if (id < my_id) { is_mob_host = false; break; }
}
}
if (impl_->multiplayer) {
impl_->net_pos_timer += dt;
if (impl_->net_pos_timer >= 0.05f) { // ~20 Hz
Expand Down
19 changes: 14 additions & 5 deletions srcs/mob/mob_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ static constexpr float ZOMBIE_SPEED = 0.9f; // blocks/sec
static constexpr float DETECT_RANGE = 16.0f; // start chasing
static constexpr float LOSE_RANGE = 26.0f; // give up chasing
static constexpr float ATTACK_RANGE = 1.5f; // deal damage
static constexpr float ATTACK_Y_RANGE = 2.5f; // vertical reach for zombie attack
static constexpr float MELEE_Y_RANGE = 2.5f; // vertical reach for player melee
static constexpr float ATTACK_DAMAGE = 2.0f; // HP per hit
static constexpr float ATTACK_PERIOD = 1.0f; // seconds between hits
static constexpr float PLAYER_EYE_H = 1.62f;
Expand Down Expand Up @@ -114,11 +116,15 @@ void MobManager::updateZombie(Zombie& z, float dt,
const int ti = nearestTarget(z, targets);
// Player feet position
const float pfx = (ti >= 0) ? targets[ti].x : z.x;
const float pfy = (ti >= 0) ? targets[ti].y - PLAYER_EYE_H : z.y;
const float pfz = (ti >= 0) ? targets[ti].z : z.z;

const float dx = pfx - z.x;
const float dy = pfy - z.y;
const float dz = pfz - z.z;
const float horiz = (ti >= 0) ? std::sqrt(dx * dx + dz * dz) : 1e30f;
// Y range check: player feet must be within zombie's vertical reach
const bool y_in_attack = (dy > -1.0f && dy < ZOMBIE_HEIGHT + 0.5f);

// ── State transitions ─────────────────────────────────────────────────
z.state_timer += dt;
Expand All @@ -132,13 +138,13 @@ void MobManager::updateZombie(Zombie& z, float dt,
case Zombie::State::Chase:
if (horiz > LOSE_RANGE) {
z.state = Zombie::State::Idle;
} else if (horiz < ATTACK_RANGE) {
} else if (horiz < ATTACK_RANGE && y_in_attack) {
z.state = Zombie::State::Attack;
z.state_timer = 0;
}
break;
case Zombie::State::Attack:
if (horiz > ATTACK_RANGE * 1.6f)
if (horiz > ATTACK_RANGE * 1.6f || !y_in_attack)
z.state = Zombie::State::Chase;
break;
case Zombie::State::Fuse:
Expand Down Expand Up @@ -179,7 +185,7 @@ void MobManager::updateZombie(Zombie& z, float dt,
if (z.attack_cooldown > 0) z.attack_cooldown -= dt;
if (z.state == Zombie::State::Attack && z.attack_cooldown <= 0 && ti >= 0) {
z.attack_cooldown = ATTACK_PERIOD;
out_damage[ti] += ATTACK_DAMAGE;
if (y_in_attack) out_damage[ti] += ATTACK_DAMAGE;
}
}

Expand Down Expand Up @@ -351,14 +357,17 @@ int MobManager::playerMeleeAttack(float px, float py, float pz,
static constexpr float MELEE_RANGE = 4.0f;
static constexpr float MELEE_DAMAGE = 5.0f;

const float pfx = px, pfy = py - PLAYER_EYE_H, pfz = pz;
const float pfx = px, pfz = pz;
float best_dist = MELEE_RANGE;
int best_idx = -1;

for (int i = 0; i < (int)zombies_.size(); ++i) {
const Zombie& z = zombies_[i];
if (!z.alive()) continue;
const float dx = z.x - pfx, dz = z.z - pfz;
const float dx = z.x - pfx;
const float dy = (z.y + ZOMBIE_HEIGHT * 0.5f) - py; // zombie center vs player eye
const float dz = z.z - pfz;
if (std::fabs(dy) >= MELEE_Y_RANGE) continue;
const float dist = std::sqrt(dx * dx + dz * dz);
if (dist >= best_dist) continue;
// Must be roughly in front of the player
Expand Down