Even more refactor. Getting close to done.
This commit is contained in:
@@ -18,6 +18,8 @@ sound_pool p(100);
|
||||
#include "src/world/world_fires.nvgt"
|
||||
#include "src/world/world_buildings.nvgt"
|
||||
#include "src/world/world_streams.nvgt"
|
||||
#include "src/world/mountains.nvgt"
|
||||
#include "src/world/barricade.nvgt"
|
||||
#include "src/world_state.nvgt"
|
||||
#include "src/ui.nvgt"
|
||||
#include "src/inventory.nvgt"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Barricade - base defense system
|
||||
// Protects base from zombies and bandits with reinforceable health
|
||||
|
||||
int barricade_health = 0;
|
||||
bool barricade_initialized = false;
|
||||
int residents_count = 0;
|
||||
|
||||
void init_barricade() {
|
||||
if (barricade_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
barricade_health = BARRICADE_BASE_HEALTH;
|
||||
barricade_initialized = true;
|
||||
}
|
||||
|
||||
int add_barricade_health(int amount) {
|
||||
if (amount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int before = barricade_health;
|
||||
barricade_health += amount;
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH) {
|
||||
barricade_health = BARRICADE_MAX_HEALTH;
|
||||
}
|
||||
|
||||
return barricade_health - before;
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
// Mountain ranges - elevated terrain with variable slopes and streams
|
||||
// Includes procedural generation, elevation management, and stream placement
|
||||
|
||||
class MountainRange {
|
||||
int start_position;
|
||||
int end_position;
|
||||
int[] elevations;
|
||||
string[] terrain_types;
|
||||
int[] stream_positions;
|
||||
int stream_sound_handle;
|
||||
int stream_sound_position;
|
||||
|
||||
MountainRange(int start_pos, int size) {
|
||||
start_position = start_pos;
|
||||
end_position = start_pos + size - 1;
|
||||
elevations.resize(size);
|
||||
terrain_types.resize(size);
|
||||
stream_sound_handle = -1;
|
||||
stream_sound_position = -1;
|
||||
generate_terrain();
|
||||
}
|
||||
|
||||
void generate_terrain() {
|
||||
int size = int(elevations.length());
|
||||
|
||||
// Initialize endpoints at low elevations (easier transition from flat ground)
|
||||
elevations[0] = random(0, 5);
|
||||
elevations[size - 1] = random(0, 5);
|
||||
|
||||
// Use midpoint displacement for natural terrain
|
||||
midpoint_displace(0, size - 1, 25);
|
||||
|
||||
// Clamp values to valid range
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (elevations[i] < MOUNTAIN_MIN_ELEVATION) elevations[i] = MOUNTAIN_MIN_ELEVATION;
|
||||
if (elevations[i] > MOUNTAIN_MAX_ELEVATION) elevations[i] = MOUNTAIN_MAX_ELEVATION;
|
||||
}
|
||||
|
||||
// Smooth to enforce max slope constraint
|
||||
smooth_slopes();
|
||||
|
||||
// Ensure at least one steep climb (≥7 feet) reaches into 10-20 elevation range
|
||||
ensure_steep_climb();
|
||||
|
||||
// Assign terrain types based on elevation
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (elevations[i] > 20) {
|
||||
terrain_types[i] = "snow";
|
||||
} else if (elevations[i] > 8) {
|
||||
terrain_types[i] = "stone";
|
||||
} else {
|
||||
terrain_types[i] = "gravel";
|
||||
}
|
||||
}
|
||||
|
||||
// Place streams in valley areas
|
||||
place_streams();
|
||||
}
|
||||
|
||||
void midpoint_displace(int left, int right, int roughness) {
|
||||
if (right - left <= 1) return;
|
||||
|
||||
int mid = (left + right) / 2;
|
||||
int avg = (elevations[left] + elevations[right]) / 2;
|
||||
int displacement = random(-roughness, roughness);
|
||||
elevations[mid] = avg + displacement;
|
||||
|
||||
int new_roughness = roughness * 7 / 10;
|
||||
if (new_roughness < 1) new_roughness = 1;
|
||||
|
||||
midpoint_displace(left, mid, new_roughness);
|
||||
midpoint_displace(mid, right, new_roughness);
|
||||
}
|
||||
|
||||
void smooth_slopes() {
|
||||
bool changed = true;
|
||||
int iterations = 0;
|
||||
while (changed && iterations < 100) {
|
||||
changed = false;
|
||||
iterations++;
|
||||
|
||||
for (int i = 1; i < int(elevations.length()); i++) {
|
||||
int diff = elevations[i] - elevations[i-1];
|
||||
if (diff > MOUNTAIN_MAX_SLOPE) {
|
||||
elevations[i] = elevations[i-1] + MOUNTAIN_MAX_SLOPE;
|
||||
changed = true;
|
||||
} else if (diff < -MOUNTAIN_MAX_SLOPE) {
|
||||
elevations[i] = elevations[i-1] - MOUNTAIN_MAX_SLOPE;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void place_streams() {
|
||||
// Find valley bottoms (local minima)
|
||||
int[] valleys;
|
||||
for (int i = 2; i < int(elevations.length()) - 2; i++) {
|
||||
if (elevations[i] < elevations[i-1] && elevations[i] < elevations[i+1] &&
|
||||
elevations[i] < elevations[i-2] && elevations[i] < elevations[i+2]) {
|
||||
valleys.insert_last(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Place 1-3 streams in valleys
|
||||
int num_streams = random(1, 3);
|
||||
if (num_streams > int(valleys.length())) num_streams = int(valleys.length());
|
||||
|
||||
for (int i = 0; i < num_streams && valleys.length() > 0; i++) {
|
||||
int idx = random(0, int(valleys.length()) - 1);
|
||||
stream_positions.insert_last(valleys[idx]);
|
||||
valleys.remove_at(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void ensure_steep_climb() {
|
||||
int size = int(elevations.length());
|
||||
|
||||
// Check if we already have a steep climb (≥7) to/from 10-20 elevation
|
||||
bool has_steep_climb = false;
|
||||
for (int i = 1; i < size; i++) {
|
||||
int diff = elevations[i] - elevations[i-1];
|
||||
if (diff < 0) diff = -diff;
|
||||
|
||||
if (diff >= MOUNTAIN_STEEP_THRESHOLD) {
|
||||
// Check if either elevation is in 10-20 range
|
||||
if ((elevations[i] >= 10 && elevations[i] <= 20) ||
|
||||
(elevations[i-1] >= 10 && elevations[i-1] <= 20)) {
|
||||
has_steep_climb = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no steep climb to 10-20 range, create one
|
||||
if (!has_steep_climb && size >= 10) {
|
||||
// Pick a random position in the middle 60% of the mountain
|
||||
int pos = random(int(size * 0.2), int(size * 0.8));
|
||||
|
||||
// Set up a steep climb: create elevation 15-18 with steep approach
|
||||
int target_elevation = random(15, 18);
|
||||
elevations[pos] = target_elevation;
|
||||
|
||||
// Make the approach from left steep (if possible)
|
||||
if (pos > 0) {
|
||||
elevations[pos - 1] = target_elevation - MOUNTAIN_STEEP_THRESHOLD - 1;
|
||||
if (elevations[pos - 1] < MOUNTAIN_MIN_ELEVATION) {
|
||||
elevations[pos - 1] = MOUNTAIN_MIN_ELEVATION;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the approach from right steep (if possible)
|
||||
if (pos < size - 1) {
|
||||
elevations[pos + 1] = target_elevation - MOUNTAIN_STEEP_THRESHOLD - 1;
|
||||
if (elevations[pos + 1] < MOUNTAIN_MIN_ELEVATION) {
|
||||
elevations[pos + 1] = MOUNTAIN_MIN_ELEVATION;
|
||||
}
|
||||
}
|
||||
|
||||
// Re-smooth to ensure slopes aren't too extreme elsewhere
|
||||
smooth_slopes();
|
||||
}
|
||||
|
||||
// Ensure edge transitions aren't too steep (max 20 feet from flat ground)
|
||||
// First transition: tile 0 to tile 1
|
||||
if (size >= 2) {
|
||||
int first_diff = elevations[1] - elevations[0];
|
||||
if (first_diff < 0) first_diff = -first_diff;
|
||||
if (first_diff > 20) {
|
||||
if (elevations[1] > elevations[0]) {
|
||||
elevations[1] = elevations[0] + 20;
|
||||
} else {
|
||||
elevations[1] = elevations[0] - 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Last transition: tile size-2 to tile size-1
|
||||
if (size >= 2) {
|
||||
int last_diff = elevations[size-1] - elevations[size-2];
|
||||
if (last_diff < 0) last_diff = -last_diff;
|
||||
if (last_diff > 20) {
|
||||
if (elevations[size-2] > elevations[size-1]) {
|
||||
elevations[size-2] = elevations[size-1] + 20;
|
||||
} else {
|
||||
elevations[size-2] = elevations[size-1] - 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get_elevation_at(int world_x) {
|
||||
if (world_x < start_position || world_x > end_position) return 0;
|
||||
int index = world_x - start_position;
|
||||
return elevations[index];
|
||||
}
|
||||
|
||||
string get_terrain_at(int world_x) {
|
||||
if (world_x < start_position || world_x > end_position) return "stone";
|
||||
int index = world_x - start_position;
|
||||
return terrain_types[index];
|
||||
}
|
||||
|
||||
int get_elevation_change(int from_x, int to_x) {
|
||||
int from_elev = get_elevation_at(from_x);
|
||||
int to_elev = get_elevation_at(to_x);
|
||||
return to_elev - from_elev;
|
||||
}
|
||||
|
||||
bool is_steep_section(int from_x, int to_x) {
|
||||
int change = get_elevation_change(from_x, to_x);
|
||||
if (change < 0) change = -change;
|
||||
return change >= MOUNTAIN_STEEP_THRESHOLD;
|
||||
}
|
||||
|
||||
bool contains_position(int world_x) {
|
||||
return world_x >= start_position && world_x <= end_position;
|
||||
}
|
||||
|
||||
bool is_stream_at(int world_x) {
|
||||
if (!contains_position(world_x)) return false;
|
||||
int index = world_x - start_position;
|
||||
for (uint i = 0; i < stream_positions.length(); i++) {
|
||||
if (stream_positions[i] == index) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (stream_positions.length() == 0) return;
|
||||
|
||||
// Find nearest stream to player
|
||||
int nearest_stream = -1;
|
||||
int nearest_distance = 999;
|
||||
|
||||
for (uint i = 0; i < stream_positions.length(); i++) {
|
||||
int stream_world_x = start_position + stream_positions[i];
|
||||
int distance = abs(x - stream_world_x);
|
||||
if (distance < nearest_distance) {
|
||||
nearest_distance = distance;
|
||||
nearest_stream = stream_world_x;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep nearest stream sound active so distance-based fade can work.
|
||||
if (nearest_stream != -1) {
|
||||
if (stream_sound_handle == -1 || !p.sound_is_active(stream_sound_handle)) {
|
||||
stream_sound_handle = p.play_1d("sounds/terrain/stream.ogg", x, nearest_stream, true);
|
||||
stream_sound_position = nearest_stream;
|
||||
if (stream_sound_handle != -1) {
|
||||
p.update_sound_positioning_values(stream_sound_handle, -1.0, MOUNTAIN_STREAM_VOLUME_STEP, true);
|
||||
}
|
||||
} else if (stream_sound_position != nearest_stream) {
|
||||
p.update_sound_1d(stream_sound_handle, nearest_stream);
|
||||
stream_sound_position = nearest_stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (stream_sound_handle != -1) {
|
||||
p.destroy_sound(stream_sound_handle);
|
||||
stream_sound_handle = -1;
|
||||
}
|
||||
stream_sound_position = -1;
|
||||
}
|
||||
}
|
||||
MountainRange@[] world_mountains;
|
||||
|
||||
MountainRange@ get_mountain_at(int world_x) {
|
||||
for (uint i = 0; i < world_mountains.length(); i++) {
|
||||
if (world_mountains[i].contains_position(world_x)) {
|
||||
return @world_mountains[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int get_mountain_elevation_at(int world_x) {
|
||||
MountainRange@ mountain = get_mountain_at(world_x);
|
||||
if (mountain is null) return 0;
|
||||
return mountain.get_elevation_at(world_x);
|
||||
}
|
||||
|
||||
bool is_mountain_stream_at(int world_x) {
|
||||
MountainRange@ mountain = get_mountain_at(world_x);
|
||||
if (mountain is null) return false;
|
||||
return mountain.is_stream_at(world_x);
|
||||
}
|
||||
|
||||
void update_mountains() {
|
||||
for (uint i = 0; i < world_mountains.length(); i++) {
|
||||
world_mountains[i].update();
|
||||
}
|
||||
}
|
||||
|
||||
void clear_mountains() {
|
||||
for (uint i = 0; i < world_mountains.length(); i++) {
|
||||
world_mountains[i].destroy();
|
||||
}
|
||||
world_mountains.resize(0);
|
||||
}
|
||||
+21
-348
@@ -1,15 +1,25 @@
|
||||
// World Objects
|
||||
|
||||
int barricade_health = 0;
|
||||
bool barricade_initialized = false;
|
||||
int residents_count = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// World State Orchestrator
|
||||
//
|
||||
// This file coordinates all world object updates that were previously handled here.
|
||||
// Individual world objects have been split into focused modules:
|
||||
//
|
||||
// Enemies (src/enemies/):
|
||||
// - undead.nvgt - Undead creatures (zombies, future: vampires, ghosts)
|
||||
// - bandit.nvgt - Bandit enemies with aggressive/wandering states
|
||||
// - ground_game.nvgt - Ground animals (boars, future: mountain goats, rams)
|
||||
// - flying_creatures.nvgt - Flying creatures (geese, config-driven)
|
||||
//
|
||||
// World Objects (src/world/):
|
||||
// - world_drops.nvgt - Item drops with pickup logic
|
||||
// - world_snares.nvgt - Traps for catching small game
|
||||
// - world_fires.nvgt - Fires with fuel management
|
||||
// - world_buildings.nvgt - Base buildings (Firepit, HerbGarden, Storage, etc.)
|
||||
// - world_streams.nvgt - Streams for fishing and creature spawning
|
||||
// - mountains.nvgt - Mountain ranges with procedural terrain generation
|
||||
// - barricade.nvgt - Base defense system
|
||||
|
||||
// Legacy update function - retained for compatibility
|
||||
// Note: This is largely obsolete as individual update functions are called from main loop
|
||||
void update_world_objects() {
|
||||
for (uint i = 0; i < world_snares.length(); i++) {
|
||||
world_snares[i].update();
|
||||
@@ -18,340 +28,3 @@ void update_world_objects() {
|
||||
world_fires[i].update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void init_barricade() {
|
||||
if (barricade_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
barricade_health = BARRICADE_BASE_HEALTH;
|
||||
barricade_initialized = true;
|
||||
}
|
||||
|
||||
int add_barricade_health(int amount) {
|
||||
if (amount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int before = barricade_health;
|
||||
barricade_health += amount;
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH) {
|
||||
barricade_health = BARRICADE_MAX_HEALTH;
|
||||
}
|
||||
|
||||
return barricade_health - before;
|
||||
}
|
||||
|
||||
// Zombie functions moved to src/enemies/undead.nvgt
|
||||
|
||||
|
||||
// Bandit functions moved to src/enemies/bandit.nvgt
|
||||
// Boar/GroundGame functions moved to src/enemies/ground_game.nvgt
|
||||
|
||||
|
||||
// Mountain Range Class
|
||||
class MountainRange {
|
||||
int start_position;
|
||||
int end_position;
|
||||
int[] elevations;
|
||||
string[] terrain_types;
|
||||
int[] stream_positions;
|
||||
int stream_sound_handle;
|
||||
int stream_sound_position;
|
||||
|
||||
MountainRange(int start_pos, int size) {
|
||||
start_position = start_pos;
|
||||
end_position = start_pos + size - 1;
|
||||
elevations.resize(size);
|
||||
terrain_types.resize(size);
|
||||
stream_sound_handle = -1;
|
||||
stream_sound_position = -1;
|
||||
generate_terrain();
|
||||
}
|
||||
|
||||
void generate_terrain() {
|
||||
int size = int(elevations.length());
|
||||
|
||||
// Initialize endpoints at low elevations (easier transition from flat ground)
|
||||
elevations[0] = random(0, 5);
|
||||
elevations[size - 1] = random(0, 5);
|
||||
|
||||
// Use midpoint displacement for natural terrain
|
||||
midpoint_displace(0, size - 1, 25);
|
||||
|
||||
// Clamp values to valid range
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (elevations[i] < MOUNTAIN_MIN_ELEVATION) elevations[i] = MOUNTAIN_MIN_ELEVATION;
|
||||
if (elevations[i] > MOUNTAIN_MAX_ELEVATION) elevations[i] = MOUNTAIN_MAX_ELEVATION;
|
||||
}
|
||||
|
||||
// Smooth to enforce max slope constraint
|
||||
smooth_slopes();
|
||||
|
||||
// Ensure at least one steep climb (≥7 feet) reaches into 10-20 elevation range
|
||||
ensure_steep_climb();
|
||||
|
||||
// Assign terrain types based on elevation
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (elevations[i] > 20) {
|
||||
terrain_types[i] = "snow";
|
||||
} else if (elevations[i] > 8) {
|
||||
terrain_types[i] = "stone";
|
||||
} else {
|
||||
terrain_types[i] = "gravel";
|
||||
}
|
||||
}
|
||||
|
||||
// Place streams in valley areas
|
||||
place_streams();
|
||||
}
|
||||
|
||||
void midpoint_displace(int left, int right, int roughness) {
|
||||
if (right - left <= 1) return;
|
||||
|
||||
int mid = (left + right) / 2;
|
||||
int avg = (elevations[left] + elevations[right]) / 2;
|
||||
int displacement = random(-roughness, roughness);
|
||||
elevations[mid] = avg + displacement;
|
||||
|
||||
int new_roughness = roughness * 7 / 10;
|
||||
if (new_roughness < 1) new_roughness = 1;
|
||||
|
||||
midpoint_displace(left, mid, new_roughness);
|
||||
midpoint_displace(mid, right, new_roughness);
|
||||
}
|
||||
|
||||
void smooth_slopes() {
|
||||
bool changed = true;
|
||||
int iterations = 0;
|
||||
while (changed && iterations < 100) {
|
||||
changed = false;
|
||||
iterations++;
|
||||
|
||||
for (int i = 1; i < int(elevations.length()); i++) {
|
||||
int diff = elevations[i] - elevations[i-1];
|
||||
if (diff > MOUNTAIN_MAX_SLOPE) {
|
||||
elevations[i] = elevations[i-1] + MOUNTAIN_MAX_SLOPE;
|
||||
changed = true;
|
||||
} else if (diff < -MOUNTAIN_MAX_SLOPE) {
|
||||
elevations[i] = elevations[i-1] - MOUNTAIN_MAX_SLOPE;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void place_streams() {
|
||||
// Find valley bottoms (local minima)
|
||||
int[] valleys;
|
||||
for (int i = 2; i < int(elevations.length()) - 2; i++) {
|
||||
if (elevations[i] < elevations[i-1] && elevations[i] < elevations[i+1] &&
|
||||
elevations[i] < elevations[i-2] && elevations[i] < elevations[i+2]) {
|
||||
valleys.insert_last(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Place 1-3 streams in valleys
|
||||
int num_streams = random(1, 3);
|
||||
if (num_streams > int(valleys.length())) num_streams = int(valleys.length());
|
||||
|
||||
for (int i = 0; i < num_streams && valleys.length() > 0; i++) {
|
||||
int idx = random(0, int(valleys.length()) - 1);
|
||||
stream_positions.insert_last(valleys[idx]);
|
||||
valleys.remove_at(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void ensure_steep_climb() {
|
||||
int size = int(elevations.length());
|
||||
|
||||
// Check if we already have a steep climb (≥7) to/from 10-20 elevation
|
||||
bool has_steep_climb = false;
|
||||
for (int i = 1; i < size; i++) {
|
||||
int diff = elevations[i] - elevations[i-1];
|
||||
if (diff < 0) diff = -diff;
|
||||
|
||||
if (diff >= MOUNTAIN_STEEP_THRESHOLD) {
|
||||
// Check if either elevation is in 10-20 range
|
||||
if ((elevations[i] >= 10 && elevations[i] <= 20) ||
|
||||
(elevations[i-1] >= 10 && elevations[i-1] <= 20)) {
|
||||
has_steep_climb = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no steep climb to 10-20 range, create one
|
||||
if (!has_steep_climb && size >= 10) {
|
||||
// Pick a random position in the middle 60% of the mountain
|
||||
int pos = random(int(size * 0.2), int(size * 0.8));
|
||||
|
||||
// Set up a steep climb: create elevation 15-18 with steep approach
|
||||
int target_elevation = random(15, 18);
|
||||
elevations[pos] = target_elevation;
|
||||
|
||||
// Make the approach from left steep (if possible)
|
||||
if (pos > 0) {
|
||||
elevations[pos - 1] = target_elevation - MOUNTAIN_STEEP_THRESHOLD - 1;
|
||||
if (elevations[pos - 1] < MOUNTAIN_MIN_ELEVATION) {
|
||||
elevations[pos - 1] = MOUNTAIN_MIN_ELEVATION;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the approach from right steep (if possible)
|
||||
if (pos < size - 1) {
|
||||
elevations[pos + 1] = target_elevation - MOUNTAIN_STEEP_THRESHOLD - 1;
|
||||
if (elevations[pos + 1] < MOUNTAIN_MIN_ELEVATION) {
|
||||
elevations[pos + 1] = MOUNTAIN_MIN_ELEVATION;
|
||||
}
|
||||
}
|
||||
|
||||
// Re-smooth to ensure slopes aren't too extreme elsewhere
|
||||
smooth_slopes();
|
||||
}
|
||||
|
||||
// Ensure edge transitions aren't too steep (max 20 feet from flat ground)
|
||||
// First transition: tile 0 to tile 1
|
||||
if (size >= 2) {
|
||||
int first_diff = elevations[1] - elevations[0];
|
||||
if (first_diff < 0) first_diff = -first_diff;
|
||||
if (first_diff > 20) {
|
||||
if (elevations[1] > elevations[0]) {
|
||||
elevations[1] = elevations[0] + 20;
|
||||
} else {
|
||||
elevations[1] = elevations[0] - 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Last transition: tile size-2 to tile size-1
|
||||
if (size >= 2) {
|
||||
int last_diff = elevations[size-1] - elevations[size-2];
|
||||
if (last_diff < 0) last_diff = -last_diff;
|
||||
if (last_diff > 20) {
|
||||
if (elevations[size-2] > elevations[size-1]) {
|
||||
elevations[size-2] = elevations[size-1] + 20;
|
||||
} else {
|
||||
elevations[size-2] = elevations[size-1] - 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get_elevation_at(int world_x) {
|
||||
if (world_x < start_position || world_x > end_position) return 0;
|
||||
int index = world_x - start_position;
|
||||
return elevations[index];
|
||||
}
|
||||
|
||||
string get_terrain_at(int world_x) {
|
||||
if (world_x < start_position || world_x > end_position) return "stone";
|
||||
int index = world_x - start_position;
|
||||
return terrain_types[index];
|
||||
}
|
||||
|
||||
int get_elevation_change(int from_x, int to_x) {
|
||||
int from_elev = get_elevation_at(from_x);
|
||||
int to_elev = get_elevation_at(to_x);
|
||||
return to_elev - from_elev;
|
||||
}
|
||||
|
||||
bool is_steep_section(int from_x, int to_x) {
|
||||
int change = get_elevation_change(from_x, to_x);
|
||||
if (change < 0) change = -change;
|
||||
return change >= MOUNTAIN_STEEP_THRESHOLD;
|
||||
}
|
||||
|
||||
bool contains_position(int world_x) {
|
||||
return world_x >= start_position && world_x <= end_position;
|
||||
}
|
||||
|
||||
bool is_stream_at(int world_x) {
|
||||
if (!contains_position(world_x)) return false;
|
||||
int index = world_x - start_position;
|
||||
for (uint i = 0; i < stream_positions.length(); i++) {
|
||||
if (stream_positions[i] == index) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (stream_positions.length() == 0) return;
|
||||
|
||||
// Find nearest stream to player
|
||||
int nearest_stream = -1;
|
||||
int nearest_distance = 999;
|
||||
|
||||
for (uint i = 0; i < stream_positions.length(); i++) {
|
||||
int stream_world_x = start_position + stream_positions[i];
|
||||
int distance = abs(x - stream_world_x);
|
||||
if (distance < nearest_distance) {
|
||||
nearest_distance = distance;
|
||||
nearest_stream = stream_world_x;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep nearest stream sound active so distance-based fade can work.
|
||||
if (nearest_stream != -1) {
|
||||
if (stream_sound_handle == -1 || !p.sound_is_active(stream_sound_handle)) {
|
||||
stream_sound_handle = p.play_1d("sounds/terrain/stream.ogg", x, nearest_stream, true);
|
||||
stream_sound_position = nearest_stream;
|
||||
if (stream_sound_handle != -1) {
|
||||
p.update_sound_positioning_values(stream_sound_handle, -1.0, MOUNTAIN_STREAM_VOLUME_STEP, true);
|
||||
}
|
||||
} else if (stream_sound_position != nearest_stream) {
|
||||
p.update_sound_1d(stream_sound_handle, nearest_stream);
|
||||
stream_sound_position = nearest_stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (stream_sound_handle != -1) {
|
||||
p.destroy_sound(stream_sound_handle);
|
||||
stream_sound_handle = -1;
|
||||
}
|
||||
stream_sound_position = -1;
|
||||
}
|
||||
}
|
||||
MountainRange@[] world_mountains;
|
||||
|
||||
MountainRange@ get_mountain_at(int world_x) {
|
||||
for (uint i = 0; i < world_mountains.length(); i++) {
|
||||
if (world_mountains[i].contains_position(world_x)) {
|
||||
return @world_mountains[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int get_mountain_elevation_at(int world_x) {
|
||||
MountainRange@ mountain = get_mountain_at(world_x);
|
||||
if (mountain is null) return 0;
|
||||
return mountain.get_elevation_at(world_x);
|
||||
}
|
||||
|
||||
bool is_mountain_stream_at(int world_x) {
|
||||
MountainRange@ mountain = get_mountain_at(world_x);
|
||||
if (mountain is null) return false;
|
||||
return mountain.is_stream_at(world_x);
|
||||
}
|
||||
|
||||
void update_mountains() {
|
||||
for (uint i = 0; i < world_mountains.length(); i++) {
|
||||
world_mountains[i].update();
|
||||
}
|
||||
}
|
||||
|
||||
void clear_mountains() {
|
||||
for (uint i = 0; i < world_mountains.length(); i++) {
|
||||
world_mountains[i].destroy();
|
||||
}
|
||||
world_mountains.resize(0);
|
||||
}
|
||||
|
||||
// Flying Creature functions moved to src/enemies/flying_creatures.nvgt
|
||||
|
||||
Reference in New Issue
Block a user