Fixed crash bug with snares and possibly in other places.
This commit is contained in:
+163
-110
@@ -31,6 +31,41 @@ bool has_burning_fire_in_base() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_resident_effect_multiplier() {
|
||||||
|
return blessing_resident_active ? 2 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_resident_success_chance(int base_chance) {
|
||||||
|
int chance = base_chance * get_resident_effect_multiplier();
|
||||||
|
if (chance > 100) chance = 100;
|
||||||
|
return chance;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_resident_break_chance(int base_chance) {
|
||||||
|
if (!blessing_resident_active) return base_chance;
|
||||||
|
int reduced = base_chance / get_resident_effect_multiplier();
|
||||||
|
if (reduced < 1 && base_chance > 0) reduced = 1;
|
||||||
|
return reduced;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_resident_escape_chance(int base_chance) {
|
||||||
|
if (!blessing_resident_active) return base_chance;
|
||||||
|
int reduced = base_chance / get_resident_effect_multiplier();
|
||||||
|
if (reduced < 1 && base_chance > 0) reduced = 1;
|
||||||
|
return reduced;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_resident_cooldown(int base_cooldown) {
|
||||||
|
int cooldown = base_cooldown / get_resident_effect_multiplier();
|
||||||
|
if (cooldown < 1) cooldown = 1;
|
||||||
|
return cooldown;
|
||||||
|
}
|
||||||
|
|
||||||
|
int apply_resident_damage_bonus(int damage) {
|
||||||
|
if (!blessing_resident_active) return damage;
|
||||||
|
return damage * get_resident_effect_multiplier();
|
||||||
|
}
|
||||||
|
|
||||||
void consume_food_for_residents() {
|
void consume_food_for_residents() {
|
||||||
int needed = get_food_requirement();
|
int needed = get_food_requirement();
|
||||||
if (needed <= 0) return;
|
if (needed <= 0) return;
|
||||||
@@ -77,13 +112,15 @@ void attempt_resident_fishing() {
|
|||||||
|
|
||||||
int caught = 0;
|
int caught = 0;
|
||||||
int poles_broken = 0;
|
int poles_broken = 0;
|
||||||
|
int break_chance = get_resident_break_chance(RESIDENT_TOOL_BREAK_CHANCE);
|
||||||
|
int fishing_chance = get_resident_success_chance(RESIDENT_FISHING_CHANCE);
|
||||||
for (int i = 0; i < active_fishers; i++) {
|
for (int i = 0; i < active_fishers; i++) {
|
||||||
// Check for pole breakage during use
|
// Check for pole breakage during use
|
||||||
if (random(1, 100) <= RESIDENT_TOOL_BREAK_CHANCE) {
|
if (random(1, 100) <= break_chance) {
|
||||||
poles_broken++;
|
poles_broken++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (random(1, 100) > RESIDENT_FISHING_CHANCE) continue;
|
if (random(1, 100) > fishing_chance) continue;
|
||||||
if (get_storage_count(ITEM_FISH) >= BASE_STORAGE_MAX) break;
|
if (get_storage_count(ITEM_FISH) >= BASE_STORAGE_MAX) break;
|
||||||
add_storage_count(ITEM_FISH, 1);
|
add_storage_count(ITEM_FISH, 1);
|
||||||
add_storage_fish_weight(random(FISH_WEIGHT_MIN, FISH_WEIGHT_MAX));
|
add_storage_fish_weight(random(FISH_WEIGHT_MIN, FISH_WEIGHT_MAX));
|
||||||
@@ -116,19 +153,26 @@ void attempt_resident_fish_smoking() {
|
|||||||
if (get_storage_count(ITEM_FISH) <= 0) return;
|
if (get_storage_count(ITEM_FISH) <= 0) return;
|
||||||
if (get_storage_count(ITEM_STICKS) <= 0) return;
|
if (get_storage_count(ITEM_STICKS) <= 0) return;
|
||||||
if (!has_burning_fire_in_base()) return;
|
if (!has_burning_fire_in_base()) return;
|
||||||
if (random(1, 100) > RESIDENT_SMOKE_FISH_CHANCE) return;
|
|
||||||
|
|
||||||
int weight = (storage_fish_weights.length() > 0) ? storage_fish_weights[0] : get_default_fish_weight();
|
int attempts = get_resident_effect_multiplier();
|
||||||
int yield = get_smoked_fish_yield(weight);
|
int smoke_chance = get_resident_success_chance(RESIDENT_SMOKE_FISH_CHANCE);
|
||||||
if (get_storage_count(ITEM_SMOKED_FISH) + yield > BASE_STORAGE_MAX) return;
|
for (int attempt = 0; attempt < attempts; attempt++) {
|
||||||
|
if (get_storage_count(ITEM_FISH) <= 0) return;
|
||||||
|
if (get_storage_count(ITEM_STICKS) <= 0) return;
|
||||||
|
if (random(1, 100) > smoke_chance) continue;
|
||||||
|
|
||||||
pop_storage_fish_weight();
|
int weight = (storage_fish_weights.length() > 0) ? storage_fish_weights[0] : get_default_fish_weight();
|
||||||
add_storage_count(ITEM_FISH, -1);
|
int yield = get_smoked_fish_yield(weight);
|
||||||
add_storage_count(ITEM_STICKS, -1);
|
if (get_storage_count(ITEM_SMOKED_FISH) + yield > BASE_STORAGE_MAX) return;
|
||||||
add_storage_count(ITEM_SMOKED_FISH, yield);
|
|
||||||
|
|
||||||
if (x <= BASE_END) {
|
pop_storage_fish_weight();
|
||||||
speak_with_history("Resident smoked a fish into " + yield + " smoked fish.", true);
|
add_storage_count(ITEM_FISH, -1);
|
||||||
|
add_storage_count(ITEM_STICKS, -1);
|
||||||
|
add_storage_count(ITEM_SMOKED_FISH, yield);
|
||||||
|
|
||||||
|
if (x <= BASE_END) {
|
||||||
|
speak_with_history("Resident smoked a fish into " + yield + " smoked fish.", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,12 +234,12 @@ int perform_resident_defense() {
|
|||||||
|
|
||||||
int damage = 0;
|
int damage = 0;
|
||||||
if (useSpear && get_storage_count(ITEM_SPEARS) > 0) {
|
if (useSpear && get_storage_count(ITEM_SPEARS) > 0) {
|
||||||
damage = RESIDENT_SPEAR_DAMAGE;
|
damage = apply_resident_damage_bonus(RESIDENT_SPEAR_DAMAGE);
|
||||||
// Weapons don't get consumed on use - they break via daily breakage check
|
// Weapons don't get consumed on use - they break via daily breakage check
|
||||||
// Just play the sound
|
// Just play the sound
|
||||||
play_1d_with_volume_step("sounds/weapons/spear_swing.ogg", x, BASE_END + 1, false, RESIDENT_DEFENSE_VOLUME_STEP);
|
play_1d_with_volume_step("sounds/weapons/spear_swing.ogg", x, BASE_END + 1, false, RESIDENT_DEFENSE_VOLUME_STEP);
|
||||||
} else if (get_storage_count(ITEM_SLINGS) > 0 && get_storage_count(ITEM_STONES) > 0) {
|
} else if (get_storage_count(ITEM_SLINGS) > 0 && get_storage_count(ITEM_STONES) > 0) {
|
||||||
damage = random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX);
|
damage = apply_resident_damage_bonus(random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX));
|
||||||
// Slings use stones as ammo, so consume a stone
|
// Slings use stones as ammo, so consume a stone
|
||||||
add_storage_count(ITEM_STONES, -1);
|
add_storage_count(ITEM_STONES, -1);
|
||||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", x, BASE_END + 1, false, RESIDENT_DEFENSE_VOLUME_STEP);
|
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", x, BASE_END + 1, false, RESIDENT_DEFENSE_VOLUME_STEP);
|
||||||
@@ -213,7 +257,7 @@ void attempt_resident_sling_defense() {
|
|||||||
if (get_storage_count(ITEM_SLINGS) <= 0 || get_storage_count(ITEM_STONES) <= 0) return;
|
if (get_storage_count(ITEM_SLINGS) <= 0 || get_storage_count(ITEM_STONES) <= 0) return;
|
||||||
|
|
||||||
// Cooldown between shots
|
// Cooldown between shots
|
||||||
if (resident_sling_timer.elapsed < RESIDENT_SLING_COOLDOWN) return;
|
if (resident_sling_timer.elapsed < get_resident_cooldown(RESIDENT_SLING_COOLDOWN)) return;
|
||||||
|
|
||||||
// Find nearest enemy within sling range
|
// Find nearest enemy within sling range
|
||||||
int nearestDistance = SLING_RANGE + 1;
|
int nearestDistance = SLING_RANGE + 1;
|
||||||
@@ -249,7 +293,7 @@ void attempt_resident_sling_defense() {
|
|||||||
resident_sling_timer.restart();
|
resident_sling_timer.restart();
|
||||||
add_storage_count(ITEM_STONES, -1);
|
add_storage_count(ITEM_STONES, -1);
|
||||||
|
|
||||||
int damage = random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX);
|
int damage = apply_resident_damage_bonus(random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX));
|
||||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", x, targetPos, false, RESIDENT_DEFENSE_VOLUME_STEP);
|
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", x, targetPos, false, RESIDENT_DEFENSE_VOLUME_STEP);
|
||||||
|
|
||||||
if (targetIsBandit) {
|
if (targetIsBandit) {
|
||||||
@@ -293,15 +337,16 @@ void process_daily_weapon_breakage() {
|
|||||||
// Perform breakage checks
|
// Perform breakage checks
|
||||||
int spearsBroken = 0;
|
int spearsBroken = 0;
|
||||||
int slingsBroken = 0;
|
int slingsBroken = 0;
|
||||||
|
int break_chance = get_resident_break_chance(RESIDENT_WEAPON_BREAK_CHANCE);
|
||||||
|
|
||||||
for (int i = 0; i < spearChecks; i++) {
|
for (int i = 0; i < spearChecks; i++) {
|
||||||
if (random(1, 100) <= RESIDENT_WEAPON_BREAK_CHANCE) {
|
if (random(1, 100) <= break_chance) {
|
||||||
spearsBroken++;
|
spearsBroken++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < slingChecks; i++) {
|
for (int i = 0; i < slingChecks; i++) {
|
||||||
if (random(1, 100) <= RESIDENT_WEAPON_BREAK_CHANCE) {
|
if (random(1, 100) <= break_chance) {
|
||||||
slingsBroken++;
|
slingsBroken++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,6 +382,9 @@ void attempt_resident_snare_retrieval() {
|
|||||||
// Need food in storage (same limitation as other resident tasks)
|
// Need food in storage (same limitation as other resident tasks)
|
||||||
if (!has_any_storage_food()) return;
|
if (!has_any_storage_food()) return;
|
||||||
|
|
||||||
|
int check_chance = get_resident_success_chance(RESIDENT_SNARE_CHECK_CHANCE);
|
||||||
|
int escape_chance = get_resident_escape_chance(RESIDENT_SNARE_ESCAPE_CHANCE);
|
||||||
|
|
||||||
// Check each snare that has a catch
|
// Check each snare that has a catch
|
||||||
for (int i = int(world_snares.length()) - 1; i >= 0; i--) {
|
for (int i = int(world_snares.length()) - 1; i >= 0; i--) {
|
||||||
WorldSnare@ snare = world_snares[i];
|
WorldSnare@ snare = world_snares[i];
|
||||||
@@ -344,10 +392,10 @@ void attempt_resident_snare_retrieval() {
|
|||||||
if (!snare.active) continue;
|
if (!snare.active) continue;
|
||||||
|
|
||||||
// Each snare has a chance to be checked by a resident this hour
|
// Each snare has a chance to be checked by a resident this hour
|
||||||
if (random(1, 100) > RESIDENT_SNARE_CHECK_CHANCE) continue;
|
if (random(1, 100) > check_chance) continue;
|
||||||
|
|
||||||
// Small chance the game escapes during retrieval (like normal)
|
// Small chance the game escapes during retrieval (like normal)
|
||||||
if (random(1, 100) <= RESIDENT_SNARE_ESCAPE_CHANCE) {
|
if (random(1, 100) <= escape_chance) {
|
||||||
notify("A " + snare.catch_type + " escaped while a resident checked the snare at x " + snare.position + ".");
|
notify("A " + snare.catch_type + " escaped while a resident checked the snare at x " + snare.position + ".");
|
||||||
remove_snare_at(snare.position);
|
remove_snare_at(snare.position);
|
||||||
continue;
|
continue;
|
||||||
@@ -376,7 +424,7 @@ void attempt_resident_snare_retrieval() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resident butchering - processes one game per day from storage
|
// Resident butchering - processes up to two games per day when blessed
|
||||||
void attempt_resident_butchering() {
|
void attempt_resident_butchering() {
|
||||||
// Need residents
|
// Need residents
|
||||||
if (residents_count <= 0) return;
|
if (residents_count <= 0) return;
|
||||||
@@ -391,100 +439,101 @@ void attempt_resident_butchering() {
|
|||||||
if (get_storage_count(ITEM_KNIVES) <= 0) return;
|
if (get_storage_count(ITEM_KNIVES) <= 0) return;
|
||||||
|
|
||||||
// Need a fire in base
|
// Need a fire in base
|
||||||
bool has_fire = false;
|
if (!has_burning_fire_in_base()) return;
|
||||||
for (uint i = 0; i < world_fires.length(); i++) {
|
|
||||||
if (world_fires[i].position <= BASE_END && world_fires[i].is_burning()) {
|
int attempts = get_resident_effect_multiplier();
|
||||||
has_fire = true;
|
int break_chance = get_resident_break_chance(RESIDENT_TOOL_BREAK_CHANCE);
|
||||||
break;
|
for (int attempt = 0; attempt < attempts; attempt++) {
|
||||||
|
// Need game in storage
|
||||||
|
if (get_storage_count(ITEM_SMALL_GAME) <= 0 && get_storage_count(ITEM_BOAR_CARCASSES) <= 0) return;
|
||||||
|
if (get_storage_count(ITEM_KNIVES) <= 0) return;
|
||||||
|
|
||||||
|
// Determine what to butcher (prioritize boar carcasses)
|
||||||
|
string game_type = "";
|
||||||
|
bool is_boar = false;
|
||||||
|
|
||||||
|
if (get_storage_count(ITEM_BOAR_CARCASSES) > 0) {
|
||||||
|
game_type = "boar carcass";
|
||||||
|
is_boar = true;
|
||||||
|
} else if (storage_small_game_types.length() > 0) {
|
||||||
|
game_type = storage_small_game_types[0];
|
||||||
|
} else {
|
||||||
|
game_type = "small game";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!has_fire) return;
|
|
||||||
|
|
||||||
// Determine what to butcher (prioritize boar carcasses)
|
// Calculate outputs and check storage capacity
|
||||||
string game_type = "";
|
int meat_yield = 0;
|
||||||
bool is_boar = false;
|
int skins_yield = 0;
|
||||||
|
int feathers_yield = 0;
|
||||||
|
int down_yield = 0;
|
||||||
|
int sinew_yield = 0;
|
||||||
|
|
||||||
if (get_storage_count(ITEM_BOAR_CARCASSES) > 0) {
|
if (game_type == "goose") {
|
||||||
game_type = "boar carcass";
|
meat_yield = 1;
|
||||||
is_boar = true;
|
feathers_yield = random(3, 6);
|
||||||
} else if (storage_small_game_types.length() > 0) {
|
down_yield = random(1, 3);
|
||||||
game_type = storage_small_game_types[0];
|
} else if (is_boar) {
|
||||||
} else {
|
meat_yield = random(2, 3);
|
||||||
game_type = "small game";
|
skins_yield = 3;
|
||||||
}
|
sinew_yield = 2;
|
||||||
|
} else {
|
||||||
// Calculate outputs and check storage capacity
|
meat_yield = 1;
|
||||||
int meat_yield = 0;
|
skins_yield = 1;
|
||||||
int skins_yield = 0;
|
|
||||||
int feathers_yield = 0;
|
|
||||||
int down_yield = 0;
|
|
||||||
int sinew_yield = 0;
|
|
||||||
|
|
||||||
if (game_type == "goose") {
|
|
||||||
meat_yield = 1;
|
|
||||||
feathers_yield = random(3, 6);
|
|
||||||
down_yield = random(1, 3);
|
|
||||||
} else if (is_boar) {
|
|
||||||
meat_yield = random(2, 3);
|
|
||||||
skins_yield = 3;
|
|
||||||
sinew_yield = 2;
|
|
||||||
} else {
|
|
||||||
meat_yield = 1;
|
|
||||||
skins_yield = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check storage capacity for outputs
|
|
||||||
if (meat_yield > 0 && get_storage_count(ITEM_MEAT) + meat_yield > BASE_STORAGE_MAX) return;
|
|
||||||
if (skins_yield > 0 && get_storage_count(ITEM_SKINS) + skins_yield > BASE_STORAGE_MAX) return;
|
|
||||||
if (feathers_yield > 0 && get_storage_count(ITEM_FEATHERS) + feathers_yield > BASE_STORAGE_MAX) return;
|
|
||||||
if (down_yield > 0 && get_storage_count(ITEM_DOWN) + down_yield > BASE_STORAGE_MAX) return;
|
|
||||||
if (sinew_yield > 0 && get_storage_count(ITEM_SINEW) + sinew_yield > BASE_STORAGE_MAX) return;
|
|
||||||
|
|
||||||
// Consume the game
|
|
||||||
if (is_boar) {
|
|
||||||
add_storage_count(ITEM_BOAR_CARCASSES, -1);
|
|
||||||
} else {
|
|
||||||
add_storage_count(ITEM_SMALL_GAME, -1);
|
|
||||||
if (storage_small_game_types.length() > 0) {
|
|
||||||
storage_small_game_types.remove_at(0);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check for knife breakage
|
// Check storage capacity for outputs
|
||||||
if (random(1, 100) <= RESIDENT_TOOL_BREAK_CHANCE) {
|
if (meat_yield > 0 && get_storage_count(ITEM_MEAT) + meat_yield > BASE_STORAGE_MAX) return;
|
||||||
add_storage_count(ITEM_KNIVES, -1);
|
if (skins_yield > 0 && get_storage_count(ITEM_SKINS) + skins_yield > BASE_STORAGE_MAX) return;
|
||||||
notify("A resident's knife broke while butchering.");
|
if (feathers_yield > 0 && get_storage_count(ITEM_FEATHERS) + feathers_yield > BASE_STORAGE_MAX) return;
|
||||||
}
|
if (down_yield > 0 && get_storage_count(ITEM_DOWN) + down_yield > BASE_STORAGE_MAX) return;
|
||||||
|
if (sinew_yield > 0 && get_storage_count(ITEM_SINEW) + sinew_yield > BASE_STORAGE_MAX) return;
|
||||||
|
|
||||||
// Add outputs to storage
|
// Consume the game
|
||||||
if (meat_yield > 0) add_storage_count(ITEM_MEAT, meat_yield);
|
if (is_boar) {
|
||||||
if (skins_yield > 0) add_storage_count(ITEM_SKINS, skins_yield);
|
add_storage_count(ITEM_BOAR_CARCASSES, -1);
|
||||||
if (feathers_yield > 0) add_storage_count(ITEM_FEATHERS, feathers_yield);
|
} else {
|
||||||
if (down_yield > 0) add_storage_count(ITEM_DOWN, down_yield);
|
add_storage_count(ITEM_SMALL_GAME, -1);
|
||||||
if (sinew_yield > 0) add_storage_count(ITEM_SINEW, sinew_yield);
|
if (storage_small_game_types.length() > 0) {
|
||||||
|
storage_small_game_types.remove_at(0);
|
||||||
// Build notification message
|
|
||||||
string result = "Resident butchered " + game_type + ". Added ";
|
|
||||||
string[] outputs;
|
|
||||||
if (meat_yield > 0) outputs.insert_last(meat_yield + " meat");
|
|
||||||
if (skins_yield > 0) outputs.insert_last(skins_yield + " skins");
|
|
||||||
if (feathers_yield > 0) outputs.insert_last(feathers_yield + " feathers");
|
|
||||||
if (down_yield > 0) outputs.insert_last(down_yield + " down");
|
|
||||||
if (sinew_yield > 0) outputs.insert_last(sinew_yield + " sinew");
|
|
||||||
|
|
||||||
for (uint i = 0; i < outputs.length(); i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
if (i == outputs.length() - 1) {
|
|
||||||
result += " and ";
|
|
||||||
} else {
|
|
||||||
result += ", ";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result += outputs[i];
|
|
||||||
}
|
|
||||||
result += " to storage.";
|
|
||||||
|
|
||||||
notify(result);
|
// Check for knife breakage
|
||||||
|
if (random(1, 100) <= break_chance) {
|
||||||
|
add_storage_count(ITEM_KNIVES, -1);
|
||||||
|
notify("A resident's knife broke while butchering.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add outputs to storage
|
||||||
|
if (meat_yield > 0) add_storage_count(ITEM_MEAT, meat_yield);
|
||||||
|
if (skins_yield > 0) add_storage_count(ITEM_SKINS, skins_yield);
|
||||||
|
if (feathers_yield > 0) add_storage_count(ITEM_FEATHERS, feathers_yield);
|
||||||
|
if (down_yield > 0) add_storage_count(ITEM_DOWN, down_yield);
|
||||||
|
if (sinew_yield > 0) add_storage_count(ITEM_SINEW, sinew_yield);
|
||||||
|
|
||||||
|
// Build notification message
|
||||||
|
string result = "Resident butchered " + game_type + ". Added ";
|
||||||
|
string[] outputs;
|
||||||
|
if (meat_yield > 0) outputs.insert_last(meat_yield + " meat");
|
||||||
|
if (skins_yield > 0) outputs.insert_last(skins_yield + " skins");
|
||||||
|
if (feathers_yield > 0) outputs.insert_last(feathers_yield + " feathers");
|
||||||
|
if (down_yield > 0) outputs.insert_last(down_yield + " down");
|
||||||
|
if (sinew_yield > 0) outputs.insert_last(sinew_yield + " sinew");
|
||||||
|
|
||||||
|
for (uint i = 0; i < outputs.length(); i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
if (i == outputs.length() - 1) {
|
||||||
|
result += " and ";
|
||||||
|
} else {
|
||||||
|
result += ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += outputs[i];
|
||||||
|
}
|
||||||
|
result += " to storage.";
|
||||||
|
|
||||||
|
notify(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resident resource collection
|
// Resident resource collection
|
||||||
@@ -504,14 +553,16 @@ void attempt_resident_collection() {
|
|||||||
|
|
||||||
// Each active collector has a 10% chance to collect something
|
// Each active collector has a 10% chance to collect something
|
||||||
int baskets_broken = 0;
|
int baskets_broken = 0;
|
||||||
|
int break_chance = get_resident_break_chance(RESIDENT_TOOL_BREAK_CHANCE);
|
||||||
|
int collection_chance = get_resident_success_chance(RESIDENT_COLLECTION_CHANCE);
|
||||||
for (int i = 0; i < active_collectors; i++) {
|
for (int i = 0; i < active_collectors; i++) {
|
||||||
// Check for basket breakage during use
|
// Check for basket breakage during use
|
||||||
if (random(1, 100) <= RESIDENT_TOOL_BREAK_CHANCE) {
|
if (random(1, 100) <= break_chance) {
|
||||||
baskets_broken++;
|
baskets_broken++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (random(1, 100) > RESIDENT_COLLECTION_CHANCE) continue;
|
if (random(1, 100) > collection_chance) continue;
|
||||||
|
|
||||||
// Determine what to collect (weighted random)
|
// Determine what to collect (weighted random)
|
||||||
// Sticks and vines more common, logs and stones less common
|
// Sticks and vines more common, logs and stones less common
|
||||||
@@ -573,16 +624,18 @@ void attempt_resident_foraging() {
|
|||||||
|
|
||||||
int baskets_produced = 0;
|
int baskets_produced = 0;
|
||||||
int baskets_broken = 0;
|
int baskets_broken = 0;
|
||||||
|
int break_chance = get_resident_break_chance(RESIDENT_TOOL_BREAK_CHANCE);
|
||||||
|
int forage_chance = get_resident_success_chance(RESIDENT_FORAGING_CHANCE);
|
||||||
|
|
||||||
for (int i = 0; i < active_foragers; i++) {
|
for (int i = 0; i < active_foragers; i++) {
|
||||||
// Check for basket breakage during foraging
|
// Check for basket breakage during foraging
|
||||||
if (random(1, 100) <= RESIDENT_TOOL_BREAK_CHANCE) {
|
if (random(1, 100) <= break_chance) {
|
||||||
baskets_broken++;
|
baskets_broken++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if foraging succeeds
|
// Check if foraging succeeds
|
||||||
if (random(1, 100) > RESIDENT_FORAGING_CHANCE) continue;
|
if (random(1, 100) > forage_chance) continue;
|
||||||
|
|
||||||
// Check storage capacity
|
// Check storage capacity
|
||||||
if (get_storage_count(ITEM_BASKET_FOOD) >= BASE_STORAGE_MAX) break;
|
if (get_storage_count(ITEM_BASKET_FOOD) >= BASE_STORAGE_MAX) break;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ const int BASE_STORAGE_MAX = 50;
|
|||||||
const int BLESSING_HEAL_AMOUNT = 3;
|
const int BLESSING_HEAL_AMOUNT = 3;
|
||||||
const int BLESSING_BARRICADE_REPAIR = 20;
|
const int BLESSING_BARRICADE_REPAIR = 20;
|
||||||
const int BLESSING_SPEED_DURATION = 300000;
|
const int BLESSING_SPEED_DURATION = 300000;
|
||||||
|
const int BLESSING_RESIDENT_DURATION = 300000;
|
||||||
const int BLESSING_TRIGGER_CHANCE = 10;
|
const int BLESSING_TRIGGER_CHANCE = 10;
|
||||||
const int BLESSING_WALK_SPEED = 320;
|
const int BLESSING_WALK_SPEED = 320;
|
||||||
const int FISH_WEIGHT_MIN = 1;
|
const int FISH_WEIGHT_MIN = 1;
|
||||||
|
|||||||
+26
-6
@@ -84,7 +84,12 @@ void spawn_bandit(int expansion_start, int expansion_end) {
|
|||||||
Bandit@ b = Bandit(spawn_x, expansion_start, expansion_end);
|
Bandit@ b = Bandit(spawn_x, expansion_start, expansion_end);
|
||||||
bandits.insert_last(b);
|
bandits.insert_last(b);
|
||||||
// Play looping sound that follows the bandit
|
// Play looping sound that follows the bandit
|
||||||
b.sound_handle = play_1d_with_volume_step(b.alert_sound, x, spawn_x, true, BANDIT_SOUND_VOLUME_STEP);
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
if (areaStarts.length() == 0 || range_overlaps_active_areas(spawn_x, spawn_x, areaStarts, areaEnds)) {
|
||||||
|
b.sound_handle = play_1d_with_volume_step(b.alert_sound, x, spawn_x, true, BANDIT_SOUND_VOLUME_STEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_bandit_attack_player(Bandit@ bandit) {
|
bool can_bandit_attack_player(Bandit@ bandit) {
|
||||||
@@ -174,9 +179,14 @@ void try_attack_barricade_bandit(Bandit@ bandit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_bandit(Bandit@ bandit) {
|
void update_bandit(Bandit@ bandit, bool audio_active) {
|
||||||
// Update looping sound position
|
// Update looping sound position
|
||||||
if (bandit.sound_handle != -1 && p.sound_is_active(bandit.sound_handle)) {
|
if (!audio_active) {
|
||||||
|
if (bandit.sound_handle != -1) {
|
||||||
|
p.destroy_sound(bandit.sound_handle);
|
||||||
|
bandit.sound_handle = -1;
|
||||||
|
}
|
||||||
|
} else if (bandit.sound_handle != -1 && p.sound_is_active(bandit.sound_handle)) {
|
||||||
p.update_sound_1d(bandit.sound_handle, bandit.position);
|
p.update_sound_1d(bandit.sound_handle, bandit.position);
|
||||||
} else if (bandit.sound_handle == -1 || !p.sound_is_active(bandit.sound_handle)) {
|
} else if (bandit.sound_handle == -1 || !p.sound_is_active(bandit.sound_handle)) {
|
||||||
// Restart looping sound if it stopped
|
// Restart looping sound if it stopped
|
||||||
@@ -227,7 +237,9 @@ void update_bandit(Bandit@ bandit) {
|
|||||||
bandit.wander_direction = -bandit.wander_direction;
|
bandit.wander_direction = -bandit.wander_direction;
|
||||||
} else {
|
} else {
|
||||||
bandit.position = target_x;
|
bandit.position = target_x;
|
||||||
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
|
if (audio_active) {
|
||||||
|
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Hit map boundary, reverse direction
|
// Hit map boundary, reverse direction
|
||||||
@@ -270,13 +282,21 @@ void update_bandit(Bandit@ bandit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bandit.position = target_x;
|
bandit.position = target_x;
|
||||||
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
|
if (audio_active) {
|
||||||
|
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_bandits() {
|
void update_bandits() {
|
||||||
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
bool limit_audio = (areaStarts.length() > 0);
|
||||||
|
|
||||||
for (uint i = 0; i < bandits.length(); i++) {
|
for (uint i = 0; i < bandits.length(); i++) {
|
||||||
update_bandit(bandits[i]);
|
bool audio_active = !limit_audio || range_overlaps_active_areas(bandits[i].position, bandits[i].position, areaStarts, areaEnds);
|
||||||
|
update_bandit(bandits[i], audio_active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -226,11 +226,16 @@ bool spawn_flying_creature(string creature_type) {
|
|||||||
FlyingCreature@ c = FlyingCreature(creature_type, spawn_x, area_start, area_end, cfg);
|
FlyingCreature@ c = FlyingCreature(creature_type, spawn_x, area_start, area_end, cfg);
|
||||||
flying_creatures.insert_last(c);
|
flying_creatures.insert_last(c);
|
||||||
// Play looping sound that follows the flying creature
|
// Play looping sound that follows the flying creature
|
||||||
c.sound_handle = play_1d_with_volume_step(c.voice_sound, x, spawn_x, true, cfg.sound_volume_step);
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
if (areaStarts.length() == 0 || range_overlaps_active_areas(spawn_x, spawn_x, areaStarts, areaEnds)) {
|
||||||
|
c.sound_handle = play_1d_with_volume_step(c.voice_sound, x, spawn_x, true, cfg.sound_volume_step);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_flying_creature(FlyingCreature@ creature) {
|
void update_flying_creature(FlyingCreature@ creature, bool audio_active) {
|
||||||
FlyingCreatureConfig@ cfg = get_flying_creature_config(creature.creature_type);
|
FlyingCreatureConfig@ cfg = get_flying_creature_config(creature.creature_type);
|
||||||
if (cfg is null) return;
|
if (cfg is null) return;
|
||||||
|
|
||||||
@@ -240,7 +245,11 @@ void update_flying_creature(FlyingCreature@ creature) {
|
|||||||
creature.fade_timer.restart();
|
creature.fade_timer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) {
|
if (!audio_active && creature.sound_handle != -1) {
|
||||||
|
p.destroy_sound(creature.sound_handle);
|
||||||
|
creature.sound_handle = -1;
|
||||||
|
creature.ready_to_remove = true;
|
||||||
|
} else if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) {
|
||||||
float progress = float(creature.fade_timer.elapsed) / float(FLYING_CREATURE_FADE_OUT_DURATION);
|
float progress = float(creature.fade_timer.elapsed) / float(FLYING_CREATURE_FADE_OUT_DURATION);
|
||||||
if (progress < 0.0) progress = 0.0;
|
if (progress < 0.0) progress = 0.0;
|
||||||
if (progress > 1.0) progress = 1.0;
|
if (progress > 1.0) progress = 1.0;
|
||||||
@@ -265,7 +274,12 @@ void update_flying_creature(FlyingCreature@ creature) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update looping sound position
|
// Update looping sound position
|
||||||
if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) {
|
if (!audio_active) {
|
||||||
|
if (creature.sound_handle != -1) {
|
||||||
|
p.destroy_sound(creature.sound_handle);
|
||||||
|
creature.sound_handle = -1;
|
||||||
|
}
|
||||||
|
} else if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) {
|
||||||
p.update_sound_1d(creature.sound_handle, creature.position);
|
p.update_sound_1d(creature.sound_handle, creature.position);
|
||||||
} else if (creature.sound_handle == -1 || !p.sound_is_active(creature.sound_handle)) {
|
} else if (creature.sound_handle == -1 || !p.sound_is_active(creature.sound_handle)) {
|
||||||
// Restart looping sound if it stopped
|
// Restart looping sound if it stopped
|
||||||
@@ -301,7 +315,7 @@ void update_flying_creature(FlyingCreature@ creature) {
|
|||||||
}
|
}
|
||||||
if (target_x >= 0 && target_x < MAP_SIZE) {
|
if (target_x >= 0 && target_x < MAP_SIZE) {
|
||||||
creature.position = target_x;
|
creature.position = target_x;
|
||||||
if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) {
|
if (audio_active && creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) {
|
||||||
p.update_sound_1d(creature.sound_handle, creature.position);
|
p.update_sound_1d(creature.sound_handle, creature.position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,15 +328,18 @@ void update_flying_creature(FlyingCreature@ creature) {
|
|||||||
|
|
||||||
if (creature.fall_sound_handle != -1) {
|
if (creature.fall_sound_handle != -1) {
|
||||||
p.destroy_sound(creature.fall_sound_handle);
|
p.destroy_sound(creature.fall_sound_handle);
|
||||||
|
creature.fall_sound_handle = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
float pitch_percent = 50.0 + (50.0 * (float(creature.height) / float(cfg.max_height)));
|
float pitch_percent = 50.0 + (50.0 * (float(creature.height) / float(cfg.max_height)));
|
||||||
if (pitch_percent < 50.0) pitch_percent = 50.0;
|
if (pitch_percent < 50.0) pitch_percent = 50.0;
|
||||||
if (pitch_percent > 100.0) pitch_percent = 100.0;
|
if (pitch_percent > 100.0) pitch_percent = 100.0;
|
||||||
|
|
||||||
creature.fall_sound_handle = p.play_extended_1d(cfg.fall_sound, x, creature.position, 0, 0, true, 0, 0.0, 0.0, pitch_percent);
|
if (audio_active) {
|
||||||
if (creature.fall_sound_handle != -1) {
|
creature.fall_sound_handle = p.play_extended_1d(cfg.fall_sound, x, creature.position, 0, 0, true, 0, 0.0, 0.0, pitch_percent);
|
||||||
p.update_sound_positioning_values(creature.fall_sound_handle, -1.0, cfg.sound_volume_step, true);
|
if (creature.fall_sound_handle != -1) {
|
||||||
|
p.update_sound_positioning_values(creature.fall_sound_handle, -1.0, cfg.sound_volume_step, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (creature.height <= 0) {
|
if (creature.height <= 0) {
|
||||||
@@ -340,8 +357,14 @@ void update_flying_creature(FlyingCreature@ creature) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update_flying_creatures() {
|
void update_flying_creatures() {
|
||||||
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
bool limit_audio = (areaStarts.length() > 0);
|
||||||
|
|
||||||
for (uint i = 0; i < flying_creatures.length(); i++) {
|
for (uint i = 0; i < flying_creatures.length(); i++) {
|
||||||
update_flying_creature(flying_creatures[i]);
|
bool audio_active = !limit_audio || range_overlaps_active_areas(flying_creatures[i].position, flying_creatures[i].position, areaStarts, areaEnds);
|
||||||
|
update_flying_creature(flying_creatures[i], audio_active);
|
||||||
|
|
||||||
if (flying_creatures[i].health <= 0) {
|
if (flying_creatures[i].health <= 0) {
|
||||||
if (flying_creatures[i].state == "falling" && flying_creatures[i].height <= 0) {
|
if (flying_creatures[i].state == "falling" && flying_creatures[i].height <= 0) {
|
||||||
|
|||||||
@@ -77,7 +77,12 @@ void spawn_ground_game(int expansion_start, int expansion_end) {
|
|||||||
GroundGame@ b = GroundGame(spawn_x, expansion_start, expansion_end, "boar");
|
GroundGame@ b = GroundGame(spawn_x, expansion_start, expansion_end, "boar");
|
||||||
ground_games.insert_last(b);
|
ground_games.insert_last(b);
|
||||||
// Play looping sound that follows the boar
|
// Play looping sound that follows the boar
|
||||||
b.sound_handle = play_1d_with_volume_step(b.voice_sound, x, spawn_x, true, BOAR_SOUND_VOLUME_STEP);
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
if (areaStarts.length() == 0 || range_overlaps_active_areas(spawn_x, spawn_x, areaStarts, areaEnds)) {
|
||||||
|
b.sound_handle = play_1d_with_volume_step(b.voice_sound, x, spawn_x, true, BOAR_SOUND_VOLUME_STEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_ground_game_attack_player(GroundGame@ game) {
|
bool can_ground_game_attack_player(GroundGame@ game) {
|
||||||
@@ -109,9 +114,14 @@ bool try_attack_player_ground_game(GroundGame@ game) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_ground_game(GroundGame@ game) {
|
void update_ground_game(GroundGame@ game, bool audio_active) {
|
||||||
// Update looping sound position
|
// Update looping sound position
|
||||||
if (game.sound_handle != -1 && p.sound_is_active(game.sound_handle)) {
|
if (!audio_active) {
|
||||||
|
if (game.sound_handle != -1) {
|
||||||
|
p.destroy_sound(game.sound_handle);
|
||||||
|
game.sound_handle = -1;
|
||||||
|
}
|
||||||
|
} else if (game.sound_handle != -1 && p.sound_is_active(game.sound_handle)) {
|
||||||
p.update_sound_1d(game.sound_handle, game.position);
|
p.update_sound_1d(game.sound_handle, game.position);
|
||||||
} else if (game.sound_handle == -1 || !p.sound_is_active(game.sound_handle)) {
|
} else if (game.sound_handle == -1 || !p.sound_is_active(game.sound_handle)) {
|
||||||
// Restart looping sound if it stopped for some reason
|
// Restart looping sound if it stopped for some reason
|
||||||
@@ -153,7 +163,9 @@ void update_ground_game(GroundGame@ game) {
|
|||||||
// Don't leave area or enter base
|
// Don't leave area or enter base
|
||||||
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
|
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
|
||||||
game.position = target;
|
game.position = target;
|
||||||
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
|
if (audio_active) {
|
||||||
|
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Wandering
|
// Wandering
|
||||||
@@ -166,7 +178,9 @@ void update_ground_game(GroundGame@ game) {
|
|||||||
// Don't leave area or enter base
|
// Don't leave area or enter base
|
||||||
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
|
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
|
||||||
game.position = target;
|
game.position = target;
|
||||||
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
|
if (audio_active) {
|
||||||
|
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
game.wander_direction = -game.wander_direction; // Turn around
|
game.wander_direction = -game.wander_direction; // Turn around
|
||||||
}
|
}
|
||||||
@@ -175,8 +189,14 @@ void update_ground_game(GroundGame@ game) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update_ground_games() {
|
void update_ground_games() {
|
||||||
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
bool limit_audio = (areaStarts.length() > 0);
|
||||||
|
|
||||||
for (uint i = 0; i < ground_games.length(); i++) {
|
for (uint i = 0; i < ground_games.length(); i++) {
|
||||||
update_ground_game(ground_games[i]);
|
bool audio_active = !limit_audio || range_overlaps_active_areas(ground_games[i].position, ground_games[i].position, areaStarts, areaEnds);
|
||||||
|
update_ground_game(ground_games[i], audio_active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-5
@@ -62,7 +62,12 @@ void spawn_undead() {
|
|||||||
Undead@ z = Undead(spawn_x, "zombie");
|
Undead@ z = Undead(spawn_x, "zombie");
|
||||||
undeads.insert_last(z);
|
undeads.insert_last(z);
|
||||||
// Play looping sound that follows the zombie
|
// Play looping sound that follows the zombie
|
||||||
z.sound_handle = play_1d_with_volume_step(z.voice_sound, x, spawn_x, true, ZOMBIE_SOUND_VOLUME_STEP);
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
if (areaStarts.length() == 0 || range_overlaps_active_areas(spawn_x, spawn_x, areaStarts, areaEnds)) {
|
||||||
|
z.sound_handle = play_1d_with_volume_step(z.voice_sound, x, spawn_x, true, ZOMBIE_SOUND_VOLUME_STEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void try_attack_barricade_undead(Undead@ undead) {
|
void try_attack_barricade_undead(Undead@ undead) {
|
||||||
@@ -128,9 +133,14 @@ bool try_attack_player_undead(Undead@ undead) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_undead(Undead@ undead) {
|
void update_undead(Undead@ undead, bool audio_active) {
|
||||||
// Update looping sound position
|
// Update looping sound position
|
||||||
if (undead.sound_handle != -1 && p.sound_is_active(undead.sound_handle)) {
|
if (!audio_active) {
|
||||||
|
if (undead.sound_handle != -1) {
|
||||||
|
p.destroy_sound(undead.sound_handle);
|
||||||
|
undead.sound_handle = -1;
|
||||||
|
}
|
||||||
|
} else if (undead.sound_handle != -1 && p.sound_is_active(undead.sound_handle)) {
|
||||||
p.update_sound_1d(undead.sound_handle, undead.position);
|
p.update_sound_1d(undead.sound_handle, undead.position);
|
||||||
} else if (undead.sound_handle == -1 || !p.sound_is_active(undead.sound_handle)) {
|
} else if (undead.sound_handle == -1 || !p.sound_is_active(undead.sound_handle)) {
|
||||||
// Restart looping sound if it stopped for some reason
|
// Restart looping sound if it stopped for some reason
|
||||||
@@ -175,7 +185,9 @@ void update_undead(Undead@ undead) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
undead.position = target_x;
|
undead.position = target_x;
|
||||||
play_creature_footstep(x, undead.position, BASE_END, GRASS_END, ZOMBIE_FOOTSTEP_MAX_DISTANCE, ZOMBIE_SOUND_VOLUME_STEP);
|
if (audio_active) {
|
||||||
|
play_creature_footstep(x, undead.position, BASE_END, GRASS_END, ZOMBIE_FOOTSTEP_MAX_DISTANCE, ZOMBIE_SOUND_VOLUME_STEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_undeads() {
|
void update_undeads() {
|
||||||
@@ -195,8 +207,14 @@ void update_undeads() {
|
|||||||
spawn_undead();
|
spawn_undead();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
bool limit_audio = (areaStarts.length() > 0);
|
||||||
|
|
||||||
for (uint i = 0; i < undeads.length(); i++) {
|
for (uint i = 0; i < undeads.length(); i++) {
|
||||||
update_undead(undeads[i]);
|
bool audio_active = !limit_audio || range_overlaps_active_areas(undeads[i].position, undeads[i].position, areaStarts, areaEnds);
|
||||||
|
update_undead(undeads[i], audio_active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-1
@@ -481,9 +481,22 @@ void normalize_tree_positions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update_environment() {
|
void update_environment() {
|
||||||
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
bool limit_audio = (areaStarts.length() > 0);
|
||||||
|
|
||||||
for(uint i = 0; i < trees.length(); i++) {
|
for(uint i = 0; i < trees.length(); i++) {
|
||||||
trees[i].update();
|
|
||||||
trees[i].try_regen();
|
trees[i].try_regen();
|
||||||
|
|
||||||
|
if (limit_audio && !range_overlaps_active_areas(trees[i].position, trees[i].position, areaStarts, areaEnds)) {
|
||||||
|
if (trees[i].sound_handle != -1) {
|
||||||
|
p.destroy_sound(trees[i].sound_handle);
|
||||||
|
trees[i].sound_handle = -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
trees[i].update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,65 @@ void check_action_menu(int x) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WorldSnare@ get_snare_within_range(int pos, int range) {
|
||||||
|
WorldSnare@ nearest = null;
|
||||||
|
int nearest_distance = range + 1;
|
||||||
|
for (uint i = 0; i < world_snares.length(); i++) {
|
||||||
|
int dist = abs(world_snares[i].position - pos);
|
||||||
|
if (dist <= range && dist < nearest_distance) {
|
||||||
|
nearest_distance = dist;
|
||||||
|
@nearest = @world_snares[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nearest;
|
||||||
|
}
|
||||||
|
|
||||||
|
string get_fire_intensity_label(int fuel_remaining) {
|
||||||
|
int hours_remaining = fuel_remaining / 60000;
|
||||||
|
if (hours_remaining >= 8) return "Giant blaze";
|
||||||
|
if (hours_remaining >= 2) return "Small fire";
|
||||||
|
return "A few glowing coals";
|
||||||
|
}
|
||||||
|
|
||||||
|
string get_fire_time_estimate(int fuel_remaining) {
|
||||||
|
int approx_hours = (fuel_remaining + 30000) / 60000;
|
||||||
|
if (approx_hours <= 0) return "less than 1 hour";
|
||||||
|
if (approx_hours == 1) return "approximately 1 hour";
|
||||||
|
return "approximately " + approx_hours + " hours";
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_fire_status(WorldFire@ fire) {
|
||||||
|
if (fire == null) {
|
||||||
|
speak_with_history("No fire nearby.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string label = get_fire_intensity_label(fire.fuel_remaining);
|
||||||
|
string estimate = get_fire_time_estimate(fire.fuel_remaining);
|
||||||
|
speak_with_history(label + ". " + estimate + " remaining.", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_snare_status(WorldSnare@ snare) {
|
||||||
|
if (snare == null) {
|
||||||
|
speak_with_history("No snare nearby.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (snare.has_catch) {
|
||||||
|
speak_with_history("Snare holds a " + snare.catch_type + ".", true);
|
||||||
|
} else if (!snare.active) {
|
||||||
|
speak_with_history("Snare is set but not active yet.", true);
|
||||||
|
} else {
|
||||||
|
speak_with_history("Snare is set and empty.", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_fishing_status() {
|
||||||
|
if (fish_on_line) {
|
||||||
|
speak_with_history("Fish on the line.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
speak_with_history("No fish on the line.", true);
|
||||||
|
}
|
||||||
|
|
||||||
void try_place_snare(int x) {
|
void try_place_snare(int x) {
|
||||||
if (get_personal_count(ITEM_SNARES) > 0) {
|
if (get_personal_count(ITEM_SNARES) > 0) {
|
||||||
// Prevent placing in base area
|
// Prevent placing in base area
|
||||||
@@ -153,10 +212,13 @@ void run_action_menu(int x) {
|
|||||||
int selection = 0;
|
int selection = 0;
|
||||||
string[] options;
|
string[] options;
|
||||||
int[] action_types; // Track what action each option corresponds to
|
int[] action_types; // Track what action each option corresponds to
|
||||||
|
const int check_range = 2;
|
||||||
|
|
||||||
// Check if fire is nearby
|
// Check if fire is nearby
|
||||||
WorldFire@ nearby_fire = get_fire_near(x);
|
WorldFire@ nearby_fire = get_fire_near(x);
|
||||||
bool can_feed_fire = nearby_fire != null;
|
bool can_feed_fire = nearby_fire != null;
|
||||||
|
WorldFire@ check_fire = get_fire_within_range(x, check_range);
|
||||||
|
WorldSnare@ check_snare = get_snare_within_range(x, check_range);
|
||||||
|
|
||||||
// Build menu options dynamically
|
// Build menu options dynamically
|
||||||
options.insert_last("Place Snare");
|
options.insert_last("Place Snare");
|
||||||
@@ -182,6 +244,19 @@ void run_action_menu(int x) {
|
|||||||
action_types.insert_last(4);
|
action_types.insert_last(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_fire != null) {
|
||||||
|
options.insert_last("Check fire");
|
||||||
|
action_types.insert_last(5);
|
||||||
|
}
|
||||||
|
if (check_snare != null) {
|
||||||
|
options.insert_last("Check snare");
|
||||||
|
action_types.insert_last(6);
|
||||||
|
}
|
||||||
|
if (line_in_water || fish_on_line || is_reeling || is_casting) {
|
||||||
|
options.insert_last("Check fishing pole");
|
||||||
|
action_types.insert_last(7);
|
||||||
|
}
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
wait(5);
|
wait(5);
|
||||||
menu_background_tick();
|
menu_background_tick();
|
||||||
@@ -214,6 +289,12 @@ void run_action_menu(int x) {
|
|||||||
try_feed_fire_log(nearby_fire);
|
try_feed_fire_log(nearby_fire);
|
||||||
} else if (action == 4) {
|
} else if (action == 4) {
|
||||||
try_burn_incense();
|
try_burn_incense();
|
||||||
|
} else if (action == 5) {
|
||||||
|
check_fire_status(check_fire);
|
||||||
|
} else if (action == 6) {
|
||||||
|
check_snare_status(check_snare);
|
||||||
|
} else if (action == 7) {
|
||||||
|
check_fishing_status();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -230,6 +311,12 @@ void run_action_menu(int x) {
|
|||||||
try_feed_fire_log_max(nearby_fire);
|
try_feed_fire_log_max(nearby_fire);
|
||||||
} else if (action == 4) {
|
} else if (action == 4) {
|
||||||
try_burn_incense_max();
|
try_burn_incense_max();
|
||||||
|
} else if (action == 5) {
|
||||||
|
check_fire_status(check_fire);
|
||||||
|
} else if (action == 6) {
|
||||||
|
check_snare_status(check_snare);
|
||||||
|
} else if (action == 7) {
|
||||||
|
check_fishing_status();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,11 @@ void run_base_info_menu() {
|
|||||||
int selection = 0;
|
int selection = 0;
|
||||||
string[] options;
|
string[] options;
|
||||||
options.insert_last("Barricade health " + barricade_health + " of " + BARRICADE_MAX_HEALTH);
|
options.insert_last("Barricade health " + barricade_health + " of " + BARRICADE_MAX_HEALTH);
|
||||||
options.insert_last("Residents " + residents_count);
|
string resident_status = "Residents " + residents_count;
|
||||||
|
if (blessing_resident_active) {
|
||||||
|
resident_status += " (blessed)";
|
||||||
|
}
|
||||||
|
options.insert_last(resident_status);
|
||||||
|
|
||||||
if (world_storages.length() > 0) {
|
if (world_storages.length() > 0) {
|
||||||
options.insert_last("Storage built. Total items " + get_storage_total_items());
|
options.insert_last("Storage built. Total items " + get_storage_total_items());
|
||||||
|
|||||||
+3
-1
@@ -26,7 +26,9 @@ void notify(string message) {
|
|||||||
|
|
||||||
void update_notifications() {
|
void update_notifications() {
|
||||||
if (notification_queue.length() == 0) {
|
if (notification_queue.length() == 0) {
|
||||||
notification_active = false;
|
if (notification_active && notification_timer.elapsed >= NOTIFICATION_DELAY) {
|
||||||
|
notification_active = false;
|
||||||
|
}
|
||||||
notification_sound_handle = -1;
|
notification_sound_handle = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ int incense_hours_remaining = 0;
|
|||||||
bool incense_burning = false;
|
bool incense_burning = false;
|
||||||
bool blessing_speed_active = false;
|
bool blessing_speed_active = false;
|
||||||
timer blessing_speed_timer;
|
timer blessing_speed_timer;
|
||||||
|
bool blessing_resident_active = false;
|
||||||
|
timer blessing_resident_timer;
|
||||||
|
|
||||||
// Timers
|
// Timers
|
||||||
timer walktimer;
|
timer walktimer;
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ void reset_game_state() {
|
|||||||
incense_hours_remaining = 0;
|
incense_hours_remaining = 0;
|
||||||
incense_burning = false;
|
incense_burning = false;
|
||||||
blessing_speed_active = false;
|
blessing_speed_active = false;
|
||||||
|
blessing_resident_active = false;
|
||||||
|
|
||||||
// Reset inventory using the registry system
|
// Reset inventory using the registry system
|
||||||
reset_inventory();
|
reset_inventory();
|
||||||
@@ -978,7 +979,12 @@ bool load_game_state() {
|
|||||||
|
|
||||||
bandits.insert_last(b);
|
bandits.insert_last(b);
|
||||||
// Start looping sound for loaded bandit
|
// Start looping sound for loaded bandit
|
||||||
b.sound_handle = play_1d_with_volume_step(b.alert_sound, x, b.position, true, BANDIT_SOUND_VOLUME_STEP);
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
if (areaStarts.length() == 0 || range_overlaps_active_areas(b.position, b.position, areaStarts, areaEnds)) {
|
||||||
|
b.sound_handle = play_1d_with_volume_step(b.alert_sound, x, b.position, true, BANDIT_SOUND_VOLUME_STEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] mountainData = get_string_list_or_split(saveData, "mountains_data");
|
string[] mountainData = get_string_list_or_split(saveData, "mountains_data");
|
||||||
|
|||||||
+35
-1
@@ -317,6 +317,10 @@ void update_blessings() {
|
|||||||
update_max_health_from_equipment();
|
update_max_health_from_equipment();
|
||||||
speak_with_history("The speed blessing fades.", true);
|
speak_with_history("The speed blessing fades.", true);
|
||||||
}
|
}
|
||||||
|
if (blessing_resident_active && blessing_resident_timer.elapsed >= BLESSING_RESIDENT_DURATION) {
|
||||||
|
blessing_resident_active = false;
|
||||||
|
speak_with_history("The residents' purpose fades.", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void attempt_blessing() {
|
void attempt_blessing() {
|
||||||
@@ -328,6 +332,7 @@ void attempt_blessing() {
|
|||||||
if (player_health < max_health) options.insert_last(0);
|
if (player_health < max_health) options.insert_last(0);
|
||||||
if (!blessing_speed_active) options.insert_last(1);
|
if (!blessing_speed_active) options.insert_last(1);
|
||||||
if (barricade_health < BARRICADE_MAX_HEALTH) options.insert_last(2);
|
if (barricade_health < BARRICADE_MAX_HEALTH) options.insert_last(2);
|
||||||
|
if (residents_count > 0 && !blessing_resident_active) options.insert_last(3);
|
||||||
if (options.length() == 0) return;
|
if (options.length() == 0) return;
|
||||||
|
|
||||||
int choice = options[random(0, options.length() - 1)];
|
int choice = options[random(0, options.length() - 1)];
|
||||||
@@ -358,6 +363,10 @@ void attempt_blessing() {
|
|||||||
? "A divine force repairs the barricade. +" + gained + " health."
|
? "A divine force repairs the barricade. +" + gained + " health."
|
||||||
: "A divine force surrounds the barricade.";
|
: "A divine force surrounds the barricade.";
|
||||||
notify(god_name + " favor shines upon you. " + bonus);
|
notify(god_name + " favor shines upon you. " + bonus);
|
||||||
|
} else if (choice == 3) {
|
||||||
|
blessing_resident_active = true;
|
||||||
|
blessing_resident_timer.restart();
|
||||||
|
notify(god_name + " radiance fills residents with purpose.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,7 +410,7 @@ void update_time() {
|
|||||||
|
|
||||||
if (is_daytime && residents_count > 0 && barricade_health < BARRICADE_MAX_HEALTH && current_hour % 4 == 0) {
|
if (is_daytime && residents_count > 0 && barricade_health < BARRICADE_MAX_HEALTH && current_hour % 4 == 0) {
|
||||||
if (has_any_storage_food()) {
|
if (has_any_storage_food()) {
|
||||||
int gained = add_barricade_health(residents_count);
|
int gained = add_barricade_health(residents_count * get_resident_effect_multiplier());
|
||||||
if (gained > 0 && x <= BASE_END) {
|
if (gained > 0 && x <= BASE_END) {
|
||||||
speak_with_history("Residents repaired the barricade. +" + gained + " health.", true);
|
speak_with_history("Residents repaired the barricade. +" + gained + " health.", true);
|
||||||
}
|
}
|
||||||
@@ -527,6 +536,31 @@ void start_crossfade(bool to_night) {
|
|||||||
void update_crossfade() {
|
void update_crossfade() {
|
||||||
if (!crossfade_active) return;
|
if (!crossfade_active) return;
|
||||||
|
|
||||||
|
// If a handle went inactive mid-fade, cancel and restart ambience to avoid fading unrelated sounds.
|
||||||
|
if (crossfade_to_night) {
|
||||||
|
if (day_sound_handle == -1 || !p.sound_is_active(day_sound_handle)) {
|
||||||
|
crossfade_active = false;
|
||||||
|
update_ambience(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (night_sound_handle == -1 || !p.sound_is_active(night_sound_handle)) {
|
||||||
|
crossfade_active = false;
|
||||||
|
update_ambience(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (night_sound_handle == -1 || !p.sound_is_active(night_sound_handle)) {
|
||||||
|
crossfade_active = false;
|
||||||
|
update_ambience(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (day_sound_handle == -1 || !p.sound_is_active(day_sound_handle)) {
|
||||||
|
crossfade_active = false;
|
||||||
|
update_ambience(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float progress = float(crossfade_timer.elapsed) / float(CROSSFADE_DURATION);
|
float progress = float(crossfade_timer.elapsed) / float(CROSSFADE_DURATION);
|
||||||
if (progress > 1.0) progress = 1.0;
|
if (progress > 1.0) progress = 1.0;
|
||||||
|
|
||||||
|
|||||||
@@ -360,12 +360,24 @@ bool is_mountain_stream_at(int world_x) {
|
|||||||
return mountain.is_stream_at(world_x);
|
return mountain.is_stream_at(world_x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_mountains() {
|
void update_mountains_with_audio_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||||
|
bool limit_audio = (areaStarts.length() > 0);
|
||||||
for (uint i = 0; i < world_mountains.length(); i++) {
|
for (uint i = 0; i < world_mountains.length(); i++) {
|
||||||
|
if (limit_audio && !range_overlaps_active_areas(world_mountains[i].start_position, world_mountains[i].end_position, areaStarts, areaEnds)) {
|
||||||
|
world_mountains[i].destroy();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
world_mountains[i].update();
|
world_mountains[i].update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update_mountains() {
|
||||||
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
update_mountains_with_audio_areas(areaStarts, areaEnds);
|
||||||
|
}
|
||||||
|
|
||||||
void clear_mountains() {
|
void clear_mountains() {
|
||||||
for (uint i = 0; i < world_mountains.length(); i++) {
|
for (uint i = 0; i < world_mountains.length(); i++) {
|
||||||
world_mountains[i].destroy();
|
world_mountains[i].destroy();
|
||||||
|
|||||||
@@ -49,7 +49,16 @@ void add_world_drop(int pos, string type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update_world_drops() {
|
void update_world_drops() {
|
||||||
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
bool limit_audio = (areaStarts.length() > 0);
|
||||||
|
|
||||||
for (uint i = 0; i < world_drops.length(); i++) {
|
for (uint i = 0; i < world_drops.length(); i++) {
|
||||||
|
if (limit_audio && !range_overlaps_active_areas(world_drops[i].position, world_drops[i].position, areaStarts, areaEnds)) {
|
||||||
|
world_drops[i].destroy();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
world_drops[i].update();
|
world_drops[i].update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,9 +87,20 @@ void add_world_fire(int pos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update_fires() {
|
void update_fires() {
|
||||||
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
bool limit_audio = (areaStarts.length() > 0);
|
||||||
|
|
||||||
// Update all fires and remove any that have burned out
|
// Update all fires and remove any that have burned out
|
||||||
for (uint i = 0; i < world_fires.length(); i++) {
|
for (uint i = 0; i < world_fires.length(); i++) {
|
||||||
world_fires[i].update();
|
world_fires[i].update();
|
||||||
|
if (limit_audio && !range_overlaps_active_areas(world_fires[i].position, world_fires[i].position, areaStarts, areaEnds)) {
|
||||||
|
if (world_fires[i].sound_handle != -1) {
|
||||||
|
p.destroy_sound(world_fires[i].sound_handle);
|
||||||
|
world_fires[i].sound_handle = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove dead fires
|
// Remove dead fires
|
||||||
|
|||||||
@@ -149,7 +149,19 @@ void check_snare_collision(int player_x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update_snares() {
|
void update_snares() {
|
||||||
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
bool limit_audio = (areaStarts.length() > 0);
|
||||||
|
|
||||||
for (int i = int(world_snares.length()) - 1; i >= 0; i--) {
|
for (int i = int(world_snares.length()) - 1; i >= 0; i--) {
|
||||||
world_snares[i].update();
|
WorldSnare@ snare = world_snares[i];
|
||||||
|
snare.update();
|
||||||
|
if (limit_audio && !range_overlaps_active_areas(snare.position, snare.position, areaStarts, areaEnds)) {
|
||||||
|
if (snare.sound_handle != -1) {
|
||||||
|
p.destroy_sound(snare.sound_handle);
|
||||||
|
snare.sound_handle = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,15 +66,120 @@ class WorldStream {
|
|||||||
}
|
}
|
||||||
WorldStream@[] world_streams;
|
WorldStream@[] world_streams;
|
||||||
|
|
||||||
|
string get_expanded_area_type(int index) {
|
||||||
|
string terrain = expanded_terrain_types[index];
|
||||||
|
if (terrain.find("mountain:") == 0) {
|
||||||
|
return "mountain";
|
||||||
|
}
|
||||||
|
return terrain;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_audio_area_bounds_for_position(int pos, int &out areaStart, int &out areaEnd) {
|
||||||
|
if (pos <= BASE_END) {
|
||||||
|
areaStart = 0;
|
||||||
|
areaEnd = BASE_END;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pos <= GRASS_END) {
|
||||||
|
areaStart = BASE_END + 1;
|
||||||
|
areaEnd = GRASS_END;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pos <= GRAVEL_END) {
|
||||||
|
areaStart = GRAVEL_START;
|
||||||
|
areaEnd = GRAVEL_END;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expanded_area_start == -1 || pos < expanded_area_start || pos > expanded_area_end) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = pos - expanded_area_start;
|
||||||
|
int total = int(expanded_terrain_types.length());
|
||||||
|
if (index < 0 || index >= total) return false;
|
||||||
|
|
||||||
|
string areaType = get_expanded_area_type(index);
|
||||||
|
int left = index;
|
||||||
|
while (left > 0) {
|
||||||
|
if (get_expanded_area_type(left - 1) != areaType) break;
|
||||||
|
left--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int right = index;
|
||||||
|
while (right + 1 < total) {
|
||||||
|
if (get_expanded_area_type(right + 1) != areaType) break;
|
||||||
|
right++;
|
||||||
|
}
|
||||||
|
|
||||||
|
areaStart = expanded_area_start + left;
|
||||||
|
areaEnd = expanded_area_start + right;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_active_audio_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||||
|
areaStarts.resize(0);
|
||||||
|
areaEnds.resize(0);
|
||||||
|
|
||||||
|
int currentStart = 0;
|
||||||
|
int currentEnd = 0;
|
||||||
|
if (!get_audio_area_bounds_for_position(x, currentStart, currentEnd)) return;
|
||||||
|
|
||||||
|
areaStarts.insert_last(currentStart);
|
||||||
|
areaEnds.insert_last(currentEnd);
|
||||||
|
|
||||||
|
if (currentStart > 0) {
|
||||||
|
int prevStart = 0;
|
||||||
|
int prevEnd = 0;
|
||||||
|
if (get_audio_area_bounds_for_position(currentStart - 1, prevStart, prevEnd)) {
|
||||||
|
if (prevStart != currentStart || prevEnd != currentEnd) {
|
||||||
|
areaStarts.insert_last(prevStart);
|
||||||
|
areaEnds.insert_last(prevEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentEnd + 1 < MAP_SIZE) {
|
||||||
|
int nextStart = 0;
|
||||||
|
int nextEnd = 0;
|
||||||
|
if (get_audio_area_bounds_for_position(currentEnd + 1, nextStart, nextEnd)) {
|
||||||
|
if (nextStart != currentStart || nextEnd != currentEnd) {
|
||||||
|
areaStarts.insert_last(nextStart);
|
||||||
|
areaEnds.insert_last(nextEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool range_overlaps_active_areas(int rangeStart, int rangeEnd, int[]@ areaStarts, int[]@ areaEnds) {
|
||||||
|
for (uint i = 0; i < areaStarts.length(); i++) {
|
||||||
|
if (rangeEnd >= areaStarts[i] && rangeStart <= areaEnds[i]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void add_world_stream(int start_pos, int width) {
|
void add_world_stream(int start_pos, int width) {
|
||||||
WorldStream@ s = WorldStream(start_pos, width);
|
WorldStream@ s = WorldStream(start_pos, width);
|
||||||
world_streams.insert_last(s);
|
world_streams.insert_last(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_streams() {
|
void update_streams() {
|
||||||
|
int[] areaStarts;
|
||||||
|
int[] areaEnds;
|
||||||
|
get_active_audio_areas(areaStarts, areaEnds);
|
||||||
|
bool limit_audio = areaStarts.length() > 0;
|
||||||
|
|
||||||
for (uint i = 0; i < world_streams.length(); i++) {
|
for (uint i = 0; i < world_streams.length(); i++) {
|
||||||
|
if (limit_audio && !range_overlaps_active_areas(world_streams[i].start_position, world_streams[i].end_position, areaStarts, areaEnds)) {
|
||||||
|
world_streams[i].destroy();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
world_streams[i].update();
|
world_streams[i].update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_mountains_with_audio_areas(areaStarts, areaEnds);
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldStream@ get_stream_at(int pos) {
|
WorldStream@ get_stream_at(int pos) {
|
||||||
|
|||||||
@@ -17,14 +17,3 @@
|
|||||||
// - world_streams.nvgt - Streams for fishing and creature spawning
|
// - world_streams.nvgt - Streams for fishing and creature spawning
|
||||||
// - mountains.nvgt - Mountain ranges with procedural terrain generation
|
// - mountains.nvgt - Mountain ranges with procedural terrain generation
|
||||||
// - barricade.nvgt - Base defense system
|
// - 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();
|
|
||||||
}
|
|
||||||
for (uint i = 0; i < world_fires.length(); i++) {
|
|
||||||
world_fires[i].update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user