Pets can now be abandoned from the character menu. Added my format settings and format script for nvgt files. I just gotta consistantly remember to use it so that my spacing doesn't get all out of wack. lol
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
ColumnLimit: 120
|
||||
BreakBeforeBraces: Attach
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
IndentCaseLabels: true
|
||||
SortIncludes: Never
|
||||
ReflowComments: false
|
||||
PointerAlignment: Left
|
||||
ReferenceAlignment: Left
|
||||
SpaceBeforeParens: ControlStatements
|
||||
...
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Show simple usage help.
|
||||
print_usage() {
|
||||
echo "Usage: scripts/format-nvgt.sh [path/to/file.nvgt ...]"
|
||||
echo "Formats all tracked .nvgt files when no file paths are provided."
|
||||
}
|
||||
|
||||
scriptDir=""
|
||||
repoRoot=""
|
||||
filePath=""
|
||||
formattedCount=0
|
||||
targetFiles=()
|
||||
|
||||
# Help flag is optional and exits early without formatting.
|
||||
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
||||
print_usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Stop immediately if clang-format is not installed.
|
||||
if ! command -v clang-format >/dev/null 2>&1; then
|
||||
echo "clang-format is required but was not found in PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Resolve script location, then run from repo root so relative paths work.
|
||||
scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
repoRoot="$(cd "${scriptDir}/.." && pwd)"
|
||||
cd "${repoRoot}"
|
||||
|
||||
# We require the project style file to keep formatting consistent.
|
||||
if [[ ! -f ".clang-format" ]]; then
|
||||
echo "Missing .clang-format in repo root: ${repoRoot}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# No args: format every tracked .nvgt file in git.
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
mapfile -t targetFiles < <(git ls-files "*.nvgt")
|
||||
else
|
||||
# Args provided: validate each file and format only those paths.
|
||||
for filePath in "$@"; do
|
||||
if [[ ! -f "${filePath}" ]]; then
|
||||
echo "File not found: ${filePath}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${filePath}" != *.nvgt ]]; then
|
||||
echo "Only .nvgt files are supported: ${filePath}" >&2
|
||||
exit 1
|
||||
fi
|
||||
targetFiles+=("${filePath}")
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ "${#targetFiles[@]}" -eq 0 ]]; then
|
||||
echo "No .nvgt files found to format."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Force C++ parsing rules for NVGT while still using repo .clang-format.
|
||||
for filePath in "${targetFiles[@]}"; do
|
||||
clang-format -i --style=file --assume-filename=file.cpp "${filePath}"
|
||||
formattedCount=$((formattedCount + 1))
|
||||
done
|
||||
|
||||
echo -n "Formatted ${formattedCount} "
|
||||
if [[ ${formattedCount} -ne 1 ]]; then
|
||||
echo "files."
|
||||
else
|
||||
echo "file."
|
||||
fi
|
||||
|
||||
exit 0
|
||||
+50
-53
@@ -1,5 +1,17 @@
|
||||
string get_footstep_sound(int current_x, int base_end, int grass_end)
|
||||
{
|
||||
bool audio_asset_exists(const string& in soundFile) {
|
||||
if (file_exists(soundFile)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
pack @activePack = cast<pack @>(sound_default_pack);
|
||||
if (@activePack != null && activePack.file_exists(soundFile)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string get_footstep_sound(int current_x, int base_end, int grass_end) {
|
||||
// Check if in water first (regular streams or mountain streams)
|
||||
if (is_deep_stream_at(current_x)) {
|
||||
return "sounds/terrain/deep_water.ogg";
|
||||
@@ -13,25 +25,18 @@ string get_footstep_sound(int current_x, int base_end, int grass_end)
|
||||
return "sounds/terrain/hard_stone.ogg";
|
||||
}
|
||||
|
||||
if (current_x <= base_end)
|
||||
{
|
||||
if (current_x <= base_end) {
|
||||
// Base area
|
||||
return "sounds/terrain/wood.ogg";
|
||||
}
|
||||
else if (current_x <= grass_end)
|
||||
{
|
||||
} else if (current_x <= grass_end) {
|
||||
// Grass area
|
||||
return "sounds/terrain/grass.ogg";
|
||||
}
|
||||
else if (current_x <= GRAVEL_END)
|
||||
{
|
||||
} else if (current_x <= GRAVEL_END) {
|
||||
// Gravel area
|
||||
return "sounds/terrain/gravel.ogg";
|
||||
}
|
||||
else if (expanded_area_start != -1 && current_x >= expanded_area_start && current_x <= expanded_area_end)
|
||||
{
|
||||
} else if (expanded_area_start != -1 && current_x >= expanded_area_start && current_x <= expanded_area_end) {
|
||||
// Check for mountain terrain first
|
||||
MountainRange@ mountain = get_mountain_at(current_x);
|
||||
MountainRange @mountain = get_mountain_at(current_x);
|
||||
if (mountain !is null) {
|
||||
string terrain = mountain.get_terrain_at(current_x);
|
||||
if (terrain == "stone") {
|
||||
@@ -49,8 +54,7 @@ string get_footstep_sound(int current_x, int base_end, int grass_end)
|
||||
|
||||
// Regular expanded area - check terrain type
|
||||
int index = current_x - expanded_area_start;
|
||||
if (index >= 0 && index < int(expanded_terrain_types.length()))
|
||||
{
|
||||
if (index >= 0 && index < int(expanded_terrain_types.length())) {
|
||||
string terrain = expanded_terrain_types[index];
|
||||
// Handle "mountain:terrain" format from older saves
|
||||
if (terrain.find("mountain:") == 0) {
|
||||
@@ -76,47 +80,39 @@ string get_footstep_sound(int current_x, int base_end, int grass_end)
|
||||
return "sounds/terrain/gravel.ogg";
|
||||
}
|
||||
|
||||
void play_footstep(int current_x, int base_end, int grass_end)
|
||||
{
|
||||
void play_footstep(int current_x, int base_end, int grass_end) {
|
||||
string sound_file = get_footstep_sound(current_x, base_end, grass_end);
|
||||
|
||||
if(file_exists(sound_file)) {
|
||||
if (audio_asset_exists(sound_file)) {
|
||||
p.play_stationary(sound_file, false);
|
||||
}
|
||||
}
|
||||
|
||||
int to_audio_position(int tile_x)
|
||||
{
|
||||
int to_audio_position(int tile_x) {
|
||||
return tile_x * AUDIO_TILE_SCALE;
|
||||
}
|
||||
|
||||
float to_audio_volume_step(float volume_step)
|
||||
{
|
||||
float to_audio_volume_step(float volume_step) {
|
||||
return volume_step / float(AUDIO_TILE_SCALE);
|
||||
}
|
||||
|
||||
int play_1d_tile(string sound_file, int listener_x, int sound_x, bool looping, bool persistent = false)
|
||||
{
|
||||
int play_1d_tile(string sound_file, int listener_x, int sound_x, bool looping, bool persistent = false) {
|
||||
return p.play_1d(sound_file, to_audio_position(listener_x), to_audio_position(sound_x), looping, persistent);
|
||||
}
|
||||
|
||||
bool update_sound_1d_tile(int slot, int sound_x)
|
||||
{
|
||||
bool update_sound_1d_tile(int slot, int sound_x) {
|
||||
return p.update_sound_1d(slot, to_audio_position(sound_x));
|
||||
}
|
||||
|
||||
void update_listener_tile(int listener_x)
|
||||
{
|
||||
void update_listener_tile(int listener_x) {
|
||||
p.update_listener_1d(to_audio_position(listener_x));
|
||||
}
|
||||
|
||||
void update_sound_range_1d_tile(int slot, int range_tiles)
|
||||
{
|
||||
void update_sound_range_1d_tile(int slot, int range_tiles) {
|
||||
p.update_sound_range_1d(slot, range_tiles * AUDIO_TILE_SCALE, range_tiles * AUDIO_TILE_SCALE);
|
||||
}
|
||||
|
||||
int play_1d_with_volume_step(string sound_file, int listener_x, int sound_x, bool looping, float volume_step)
|
||||
{
|
||||
int play_1d_with_volume_step(string sound_file, int listener_x, int sound_x, bool looping, float volume_step) {
|
||||
int slot = p.play_1d(sound_file, listener_x, sound_x, looping);
|
||||
if (slot != -1) {
|
||||
p.update_sound_positioning_values(slot, -1.0, volume_step, true);
|
||||
@@ -124,31 +120,29 @@ int play_1d_with_volume_step(string sound_file, int listener_x, int sound_x, boo
|
||||
return slot;
|
||||
}
|
||||
|
||||
void play_positional_footstep(int listener_x, int step_x, int base_end, int grass_end, int max_distance, float volume_step)
|
||||
{
|
||||
void play_positional_footstep(int listener_x, int step_x, int base_end, int grass_end, int max_distance,
|
||||
float volume_step) {
|
||||
if (abs(step_x - listener_x) > max_distance) {
|
||||
return;
|
||||
}
|
||||
|
||||
string sound_file = get_footstep_sound(step_x, base_end, grass_end);
|
||||
|
||||
if(file_exists(sound_file)) {
|
||||
if (audio_asset_exists(sound_file)) {
|
||||
play_1d_with_volume_step(sound_file, listener_x, step_x, false, volume_step);
|
||||
}
|
||||
}
|
||||
|
||||
void play_land_sound(int current_x, int base_end, int grass_end)
|
||||
{
|
||||
void play_land_sound(int current_x, int base_end, int grass_end) {
|
||||
// Reusing the same logic to play the terrain sound on landing
|
||||
string sound_file = get_footstep_sound(current_x, base_end, grass_end);
|
||||
|
||||
if(file_exists(sound_file)) {
|
||||
if (audio_asset_exists(sound_file)) {
|
||||
p.play_stationary(sound_file, false);
|
||||
}
|
||||
}
|
||||
|
||||
string get_item_collect_sound(string itemName)
|
||||
{
|
||||
string get_item_collect_sound(string itemName) {
|
||||
string lookupName = itemName;
|
||||
if (lookupName == "sticks") {
|
||||
lookupName = "stick";
|
||||
@@ -167,16 +161,15 @@ string get_item_collect_sound(string itemName)
|
||||
}
|
||||
|
||||
string soundFile = "sounds/items/" + lookupName + ".ogg";
|
||||
if (file_exists(soundFile)) {
|
||||
if (audio_asset_exists(soundFile)) {
|
||||
return soundFile;
|
||||
}
|
||||
return "sounds/items/miscellaneous.ogg";
|
||||
}
|
||||
|
||||
void play_item_collect_sound(string itemName)
|
||||
{
|
||||
void play_item_collect_sound(string itemName) {
|
||||
string soundFile = get_item_collect_sound(itemName);
|
||||
if (file_exists(soundFile)) {
|
||||
if (audio_asset_exists(soundFile)) {
|
||||
p.play_stationary(soundFile, false);
|
||||
}
|
||||
}
|
||||
@@ -190,14 +183,13 @@ string get_player_damage_sound() {
|
||||
|
||||
void play_player_damage_sound() {
|
||||
string soundFile = get_player_damage_sound();
|
||||
if (file_exists(soundFile)) {
|
||||
if (audio_asset_exists(soundFile)) {
|
||||
p.play_stationary(soundFile, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Safe sound handle cleanup - checks if handle is valid and sound is active before destroying
|
||||
void safe_destroy_sound(int &inout handle)
|
||||
{
|
||||
void safe_destroy_sound(int& inout handle) {
|
||||
if (handle != -1) {
|
||||
if (p.sound_is_active(handle)) {
|
||||
p.destroy_sound(handle);
|
||||
@@ -215,10 +207,13 @@ void init_master_volume() {
|
||||
|
||||
void set_game_master_volume_db(float volume_db, bool announce = true) {
|
||||
float clamped = volume_db;
|
||||
if (clamped > MASTER_VOLUME_MAX_DB) clamped = MASTER_VOLUME_MAX_DB;
|
||||
if (clamped < MASTER_VOLUME_MIN_DB) clamped = MASTER_VOLUME_MIN_DB;
|
||||
if (clamped > MASTER_VOLUME_MAX_DB)
|
||||
clamped = MASTER_VOLUME_MAX_DB;
|
||||
if (clamped < MASTER_VOLUME_MIN_DB)
|
||||
clamped = MASTER_VOLUME_MIN_DB;
|
||||
|
||||
if (clamped == master_volume_db) return;
|
||||
if (clamped == master_volume_db)
|
||||
return;
|
||||
|
||||
master_volume_db = clamped;
|
||||
sound_master_volume = master_volume_db;
|
||||
@@ -227,8 +222,10 @@ void set_game_master_volume_db(float volume_db, bool announce = true) {
|
||||
float range = MASTER_VOLUME_MAX_DB - MASTER_VOLUME_MIN_DB;
|
||||
float normalized = (master_volume_db - MASTER_VOLUME_MIN_DB) / range;
|
||||
int volumePercent = int(normalized * 100.0f + 0.5f);
|
||||
if (volumePercent < 0) volumePercent = 0;
|
||||
if (volumePercent > 100) volumePercent = 100;
|
||||
if (volumePercent < 0)
|
||||
volumePercent = 0;
|
||||
if (volumePercent > 100)
|
||||
volumePercent = 100;
|
||||
screen_reader_speak("Volume " + volumePercent + ".", true);
|
||||
}
|
||||
}
|
||||
|
||||
+243
-146
@@ -1,6 +1,7 @@
|
||||
// Base automation helpers
|
||||
int get_food_requirement() {
|
||||
if (residents_count <= 0) return 0;
|
||||
if (residents_count <= 0)
|
||||
return 0;
|
||||
return residents_count; // 1 food per resident per 8 hours
|
||||
}
|
||||
|
||||
@@ -13,7 +14,8 @@ bool has_any_storage_food() {
|
||||
}
|
||||
|
||||
bool has_any_streams() {
|
||||
if (world_streams.length() > 0) return true;
|
||||
if (world_streams.length() > 0)
|
||||
return true;
|
||||
for (uint i = 0; i < world_mountains.length(); i++) {
|
||||
if (world_mountains[i].stream_positions.length() > 0) {
|
||||
return true;
|
||||
@@ -36,49 +38,64 @@ int get_resident_effect_multiplier() {
|
||||
}
|
||||
|
||||
int get_horse_success_bonus() {
|
||||
if (world_stables.length() == 0) return 0;
|
||||
if (world_storages.length() == 0) return 0;
|
||||
if (horses_count <= 0) return 0;
|
||||
if (world_stables.length() == 0)
|
||||
return 0;
|
||||
if (world_storages.length() == 0)
|
||||
return 0;
|
||||
if (horses_count <= 0)
|
||||
return 0;
|
||||
int count = horses_count;
|
||||
if (count > MAX_HORSES) count = MAX_HORSES;
|
||||
if (count > MAX_HORSES)
|
||||
count = MAX_HORSES;
|
||||
return count * HORSE_SUCCESS_BONUS_PER;
|
||||
}
|
||||
|
||||
int get_horse_resident_cooldown_reduction() {
|
||||
if (world_stables.length() == 0) return 0;
|
||||
if (world_storages.length() == 0) return 0;
|
||||
if (horses_count <= 0) return 0;
|
||||
if (world_stables.length() == 0)
|
||||
return 0;
|
||||
if (world_storages.length() == 0)
|
||||
return 0;
|
||||
if (horses_count <= 0)
|
||||
return 0;
|
||||
int count = horses_count;
|
||||
if (count > MAX_HORSES) count = MAX_HORSES;
|
||||
if (count > MAX_HORSES)
|
||||
count = MAX_HORSES;
|
||||
int cooldown_range = RESIDENT_COMBAT_BASE_COOLDOWN - RESIDENT_COMBAT_TARGET_COOLDOWN;
|
||||
if (cooldown_range <= 0) return 0;
|
||||
if (cooldown_range <= 0)
|
||||
return 0;
|
||||
return (cooldown_range * count) / MAX_HORSES;
|
||||
}
|
||||
|
||||
int get_resident_success_chance(int base_chance) {
|
||||
int chance = base_chance * get_resident_effect_multiplier();
|
||||
chance += get_horse_success_bonus();
|
||||
if (chance > 100) chance = 100;
|
||||
if (chance > 100)
|
||||
chance = 100;
|
||||
return chance;
|
||||
}
|
||||
|
||||
int get_resident_break_chance(int base_chance) {
|
||||
if (!blessing_resident_active) return 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;
|
||||
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;
|
||||
if (!blessing_resident_active)
|
||||
return base_chance;
|
||||
int reduced = base_chance / get_resident_effect_multiplier();
|
||||
if (reduced < 1 && base_chance > 0) reduced = 1;
|
||||
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;
|
||||
if (cooldown < 1)
|
||||
cooldown = 1;
|
||||
return cooldown;
|
||||
}
|
||||
|
||||
@@ -100,7 +117,8 @@ int apply_resident_damage_bonus(int damage) {
|
||||
|
||||
void consume_food_for_residents() {
|
||||
int needed = get_food_requirement();
|
||||
if (needed <= 0) return;
|
||||
if (needed <= 0)
|
||||
return;
|
||||
int meat_available = get_storage_count(ITEM_MEAT);
|
||||
int smoked_fish_available = get_storage_count(ITEM_SMOKED_FISH);
|
||||
int basket_food_available = get_storage_count(ITEM_BASKET_FOOD);
|
||||
@@ -132,15 +150,21 @@ void consume_food_for_residents() {
|
||||
}
|
||||
|
||||
void attempt_resident_fishing() {
|
||||
if (!is_daytime) return;
|
||||
if (residents_count <= 0) return;
|
||||
if (get_storage_count(ITEM_FISHING_POLES) <= 0) return;
|
||||
if (!has_any_streams()) return;
|
||||
if (get_storage_count(ITEM_FISH) >= get_storage_stack_limit()) return;
|
||||
if (!is_daytime)
|
||||
return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
if (get_storage_count(ITEM_FISHING_POLES) <= 0)
|
||||
return;
|
||||
if (!has_any_streams())
|
||||
return;
|
||||
if (get_storage_count(ITEM_FISH) >= get_storage_stack_limit())
|
||||
return;
|
||||
|
||||
int active_fishers = residents_count;
|
||||
int poles = get_storage_count(ITEM_FISHING_POLES);
|
||||
if (poles < active_fishers) active_fishers = poles;
|
||||
if (poles < active_fishers)
|
||||
active_fishers = poles;
|
||||
|
||||
int caught = 0;
|
||||
int poles_broken = 0;
|
||||
@@ -152,8 +176,10 @@ void attempt_resident_fishing() {
|
||||
poles_broken++;
|
||||
continue;
|
||||
}
|
||||
if (random(1, 100) > fishing_chance) continue;
|
||||
if (get_storage_count(ITEM_FISH) >= get_storage_stack_limit()) break;
|
||||
if (random(1, 100) > fishing_chance)
|
||||
continue;
|
||||
if (get_storage_count(ITEM_FISH) >= get_storage_stack_limit())
|
||||
break;
|
||||
add_storage_count(ITEM_FISH, 1);
|
||||
add_storage_fish_weight(random(FISH_WEIGHT_MIN, FISH_WEIGHT_MAX));
|
||||
caught++;
|
||||
@@ -163,9 +189,8 @@ void attempt_resident_fishing() {
|
||||
if (poles_broken > 0) {
|
||||
add_storage_count(ITEM_FISHING_POLES, -poles_broken);
|
||||
if (x <= BASE_END) {
|
||||
string msg = (poles_broken == 1)
|
||||
? "A resident's fishing pole broke."
|
||||
: poles_broken + " fishing poles broke.";
|
||||
string msg =
|
||||
(poles_broken == 1) ? "A resident's fishing pole broke." : poles_broken + " fishing poles broke.";
|
||||
speak_with_history(msg, true);
|
||||
}
|
||||
}
|
||||
@@ -180,22 +205,31 @@ void attempt_resident_fishing() {
|
||||
}
|
||||
|
||||
void attempt_resident_fish_smoking() {
|
||||
if (!is_daytime) return;
|
||||
if (residents_count <= 0) return;
|
||||
if (get_storage_count(ITEM_FISH) <= 0) return;
|
||||
if (get_storage_count(ITEM_STICKS) <= 0) return;
|
||||
if (!has_burning_fire_in_base()) return;
|
||||
if (!is_daytime)
|
||||
return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
if (get_storage_count(ITEM_FISH) <= 0)
|
||||
return;
|
||||
if (get_storage_count(ITEM_STICKS) <= 0)
|
||||
return;
|
||||
if (!has_burning_fire_in_base())
|
||||
return;
|
||||
|
||||
int attempts = get_resident_effect_multiplier();
|
||||
int smoke_chance = get_resident_success_chance(RESIDENT_SMOKE_FISH_CHANCE);
|
||||
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;
|
||||
if (get_storage_count(ITEM_FISH) <= 0)
|
||||
return;
|
||||
if (get_storage_count(ITEM_STICKS) <= 0)
|
||||
return;
|
||||
if (random(1, 100) > smoke_chance)
|
||||
continue;
|
||||
|
||||
int weight = (storage_fish_weights.length() > 0) ? storage_fish_weights[0] : get_default_fish_weight();
|
||||
int yield = get_smoked_fish_yield(weight);
|
||||
if (get_storage_count(ITEM_SMOKED_FISH) + yield > get_storage_stack_limit()) return;
|
||||
if (get_storage_count(ITEM_SMOKED_FISH) + yield > get_storage_stack_limit())
|
||||
return;
|
||||
|
||||
pop_storage_fish_weight();
|
||||
add_storage_count(ITEM_FISH, -1);
|
||||
@@ -209,12 +243,16 @@ void attempt_resident_fish_smoking() {
|
||||
}
|
||||
|
||||
void attempt_livestock_production() {
|
||||
if (world_pastures.length() == 0) return;
|
||||
if (world_storages.length() == 0) return;
|
||||
if (livestock_count <= 0) return;
|
||||
if (world_pastures.length() == 0)
|
||||
return;
|
||||
if (world_storages.length() == 0)
|
||||
return;
|
||||
if (livestock_count <= 0)
|
||||
return;
|
||||
|
||||
int count = livestock_count;
|
||||
if (count > MAX_LIVESTOCK) count = MAX_LIVESTOCK;
|
||||
if (count > MAX_LIVESTOCK)
|
||||
count = MAX_LIVESTOCK;
|
||||
|
||||
int meat_produced = 0;
|
||||
int skins_produced = 0;
|
||||
@@ -246,9 +284,12 @@ void attempt_livestock_production() {
|
||||
if ((meat_produced > 0 || skins_produced > 0 || feathers_produced > 0) && x <= BASE_END) {
|
||||
string msg = "Livestock produced ";
|
||||
string[] outputs;
|
||||
if (meat_produced > 0) outputs.insert_last(meat_produced + " meat");
|
||||
if (skins_produced > 0) outputs.insert_last(skins_produced + " skins");
|
||||
if (feathers_produced > 0) outputs.insert_last(feathers_produced + " feathers");
|
||||
if (meat_produced > 0)
|
||||
outputs.insert_last(meat_produced + " meat");
|
||||
if (skins_produced > 0)
|
||||
outputs.insert_last(skins_produced + " skins");
|
||||
if (feathers_produced > 0)
|
||||
outputs.insert_last(feathers_produced + " feathers");
|
||||
|
||||
for (uint i = 0; i < outputs.length(); i++) {
|
||||
if (i > 0) {
|
||||
@@ -266,8 +307,10 @@ void attempt_livestock_production() {
|
||||
}
|
||||
|
||||
void keep_base_fires_fed() {
|
||||
if (residents_count <= 0) return;
|
||||
if (get_storage_count(ITEM_VINES) <= 0 && get_storage_count(ITEM_STICKS) <= 0 && get_storage_count(ITEM_LOGS) <= 0) return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
if (get_storage_count(ITEM_VINES) <= 0 && get_storage_count(ITEM_STICKS) <= 0 && get_storage_count(ITEM_LOGS) <= 0)
|
||||
return;
|
||||
|
||||
// Residents tend fires once per in-game hour from time_system.
|
||||
// Keep a 1-hour buffer above the 24-hour floor so fuel does not dip below 24 between hourly checks.
|
||||
@@ -278,9 +321,12 @@ void keep_base_fires_fed() {
|
||||
const int log_fuel_ms = 720000; // 12 hours
|
||||
|
||||
for (uint i = 0; i < world_fires.length(); i++) {
|
||||
if (world_fires[i].position > BASE_END) continue;
|
||||
if (!world_fires[i].is_burning()) continue;
|
||||
if (world_fires[i].fuel_remaining >= fire_target_ms) continue;
|
||||
if (world_fires[i].position > BASE_END)
|
||||
continue;
|
||||
if (!world_fires[i].is_burning())
|
||||
continue;
|
||||
if (world_fires[i].fuel_remaining >= fire_target_ms)
|
||||
continue;
|
||||
|
||||
while (world_fires[i].fuel_remaining < fire_target_ms) {
|
||||
int needed = fire_target_ms - world_fires[i].fuel_remaining;
|
||||
@@ -333,13 +379,15 @@ bool remove_random_stored_runed_weapon(int equipType) {
|
||||
for (uint i = 0; i < runeTypes.length(); i++) {
|
||||
total += get_stored_runed_item_count(equipType, runeTypes[i]);
|
||||
}
|
||||
if (total <= 0) return false;
|
||||
if (total <= 0)
|
||||
return false;
|
||||
|
||||
int roll = random(1, total);
|
||||
int running = 0;
|
||||
for (uint i = 0; i < runeTypes.length(); i++) {
|
||||
int count = get_stored_runed_item_count(equipType, runeTypes[i]);
|
||||
if (count <= 0) continue;
|
||||
if (count <= 0)
|
||||
continue;
|
||||
running += count;
|
||||
if (roll <= running) {
|
||||
remove_stored_runed_item(equipType, runeTypes[i]);
|
||||
@@ -353,11 +401,13 @@ bool remove_random_stored_weapon(int equipType, int itemType) {
|
||||
int unrunedCount = get_storage_count(itemType);
|
||||
int runedCount = get_stored_runed_weapon_count(equipType);
|
||||
int total = unrunedCount + runedCount;
|
||||
if (total <= 0) return false;
|
||||
if (total <= 0)
|
||||
return false;
|
||||
|
||||
int roll = random(1, total);
|
||||
if (roll <= unrunedCount) {
|
||||
if (unrunedCount > 0) add_storage_count(itemType, -1);
|
||||
if (unrunedCount > 0)
|
||||
add_storage_count(itemType, -1);
|
||||
return true;
|
||||
}
|
||||
return remove_random_stored_runed_weapon(equipType);
|
||||
@@ -379,26 +429,27 @@ int get_available_defense_weapons() {
|
||||
}
|
||||
|
||||
bool can_residents_defend() {
|
||||
if (residents_count <= 0) return false;
|
||||
if (residents_count <= 0)
|
||||
return false;
|
||||
return get_available_defense_weapons() > 0;
|
||||
}
|
||||
|
||||
int choose_defense_weapon_type() {
|
||||
// Prefer bows if available
|
||||
int bowCount = (get_storage_count(ITEM_ARROWS) > 0)
|
||||
? get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS)
|
||||
: 0;
|
||||
if (bowCount > 0) return RESIDENT_WEAPON_BOW;
|
||||
int bowCount = (get_storage_count(ITEM_ARROWS) > 0) ? get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS) : 0;
|
||||
if (bowCount > 0)
|
||||
return RESIDENT_WEAPON_BOW;
|
||||
|
||||
int spearCount = get_total_stored_weapon_count(EQUIP_SPEAR, ITEM_SPEARS);
|
||||
int slingCount = (get_storage_count(ITEM_STONES) > 0)
|
||||
? get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS)
|
||||
: 0;
|
||||
int slingCount = (get_storage_count(ITEM_STONES) > 0) ? get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS) : 0;
|
||||
int total = spearCount + slingCount;
|
||||
|
||||
if (total == 0) return RESIDENT_WEAPON_SPEAR;
|
||||
if (slingCount == 0) return RESIDENT_WEAPON_SPEAR;
|
||||
if (spearCount == 0) return RESIDENT_WEAPON_SLING;
|
||||
if (total == 0)
|
||||
return RESIDENT_WEAPON_SPEAR;
|
||||
if (slingCount == 0)
|
||||
return RESIDENT_WEAPON_SPEAR;
|
||||
if (spearCount == 0)
|
||||
return RESIDENT_WEAPON_SLING;
|
||||
|
||||
int roll = random(1, total);
|
||||
return (roll <= spearCount) ? RESIDENT_WEAPON_SPEAR : RESIDENT_WEAPON_SLING;
|
||||
@@ -407,18 +458,16 @@ int choose_defense_weapon_type() {
|
||||
timer resident_combat_timer;
|
||||
|
||||
int perform_resident_defense(int target_pos) {
|
||||
if (!can_residents_defend()) return 0;
|
||||
if (resident_combat_timer.elapsed < get_resident_combat_cooldown()) return 0;
|
||||
if (!can_residents_defend())
|
||||
return 0;
|
||||
if (resident_combat_timer.elapsed < get_resident_combat_cooldown())
|
||||
return 0;
|
||||
|
||||
// Choose weapon type (bows preferred, otherwise weighted by availability)
|
||||
int weapon_type = choose_defense_weapon_type();
|
||||
int bowCount = (get_storage_count(ITEM_ARROWS) > 0)
|
||||
? get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS)
|
||||
: 0;
|
||||
int bowCount = (get_storage_count(ITEM_ARROWS) > 0) ? get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS) : 0;
|
||||
int spearCount = get_total_stored_weapon_count(EQUIP_SPEAR, ITEM_SPEARS);
|
||||
int slingCount = (get_storage_count(ITEM_STONES) > 0)
|
||||
? get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS)
|
||||
: 0;
|
||||
int slingCount = (get_storage_count(ITEM_STONES) > 0) ? get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS) : 0;
|
||||
|
||||
int damage = 0;
|
||||
if (weapon_type == RESIDENT_WEAPON_BOW && bowCount > 0) {
|
||||
@@ -432,7 +481,8 @@ int perform_resident_defense(int target_pos) {
|
||||
damage = apply_resident_damage_bonus(RESIDENT_SPEAR_DAMAGE);
|
||||
// Weapons don't get consumed on use - they break via daily breakage check
|
||||
// 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 (weapon_type == RESIDENT_WEAPON_SLING && slingCount > 0) {
|
||||
damage = apply_resident_damage_bonus(random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX));
|
||||
// Slings use stones as ammo, so consume a stone
|
||||
@@ -450,15 +500,18 @@ int perform_resident_defense(int target_pos) {
|
||||
// Proactive resident ranged defense
|
||||
void attempt_resident_ranged_defense() {
|
||||
// Only if residents exist and have ranged weapons
|
||||
if (residents_count <= 0) return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
int bowCount = get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS);
|
||||
int slingCount = get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS);
|
||||
bool has_bow = (bowCount > 0 && get_storage_count(ITEM_ARROWS) > 0);
|
||||
bool has_sling = (slingCount > 0 && get_storage_count(ITEM_STONES) > 0);
|
||||
if (!has_bow && !has_sling) return;
|
||||
if (!has_bow && !has_sling)
|
||||
return;
|
||||
|
||||
// Shared cooldown for all resident combat actions
|
||||
if (resident_combat_timer.elapsed < get_resident_combat_cooldown()) return;
|
||||
if (resident_combat_timer.elapsed < get_resident_combat_cooldown())
|
||||
return;
|
||||
|
||||
int range = has_bow ? BOW_RANGE : SLING_RANGE;
|
||||
// Find nearest enemy within range
|
||||
@@ -489,7 +542,8 @@ void attempt_resident_ranged_defense() {
|
||||
}
|
||||
|
||||
// No targets in range
|
||||
if (targetPos == -1) return;
|
||||
if (targetPos == -1)
|
||||
return;
|
||||
|
||||
// Shoot!
|
||||
resident_combat_timer.restart();
|
||||
@@ -523,13 +577,15 @@ void attempt_resident_ranged_defense() {
|
||||
}
|
||||
|
||||
void process_daily_weapon_breakage() {
|
||||
if (residents_count <= 0) return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
|
||||
int spearTotal = get_total_stored_weapon_count(EQUIP_SPEAR, ITEM_SPEARS);
|
||||
int slingTotal = get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS);
|
||||
int bowTotal = get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS);
|
||||
int totalWeapons = spearTotal + slingTotal + bowTotal;
|
||||
if (totalWeapons == 0) return;
|
||||
if (totalWeapons == 0)
|
||||
return;
|
||||
|
||||
// Number of breakage checks = min(residents, weapons)
|
||||
int checksToPerform = (residents_count < totalWeapons) ? residents_count : totalWeapons;
|
||||
@@ -545,7 +601,8 @@ void process_daily_weapon_breakage() {
|
||||
int remainingBows = bowTotal - bowChecks;
|
||||
int remaining = remainingSpears + remainingSlings + remainingBows;
|
||||
|
||||
if (remaining <= 0) break;
|
||||
if (remaining <= 0)
|
||||
break;
|
||||
|
||||
int roll = random(1, remaining);
|
||||
if (roll <= remainingSpears && remainingSpears > 0) {
|
||||
@@ -586,9 +643,8 @@ void process_daily_weapon_breakage() {
|
||||
for (int i = 0; i < spearsBroken; i++) {
|
||||
remove_random_stored_weapon(EQUIP_SPEAR, ITEM_SPEARS);
|
||||
}
|
||||
string msg = (spearsBroken == 1)
|
||||
? "A resident's spear broke from wear."
|
||||
: spearsBroken + " spears broke from wear.";
|
||||
string msg =
|
||||
(spearsBroken == 1) ? "A resident's spear broke from wear." : spearsBroken + " spears broke from wear.";
|
||||
notify(msg);
|
||||
}
|
||||
|
||||
@@ -596,9 +652,8 @@ void process_daily_weapon_breakage() {
|
||||
for (int i = 0; i < slingsBroken; i++) {
|
||||
remove_random_stored_weapon(EQUIP_SLING, ITEM_SLINGS);
|
||||
}
|
||||
string msg = (slingsBroken == 1)
|
||||
? "A resident's sling broke from wear."
|
||||
: slingsBroken + " slings broke from wear.";
|
||||
string msg =
|
||||
(slingsBroken == 1) ? "A resident's sling broke from wear." : slingsBroken + " slings broke from wear.";
|
||||
notify(msg);
|
||||
}
|
||||
|
||||
@@ -606,15 +661,14 @@ void process_daily_weapon_breakage() {
|
||||
for (int i = 0; i < bowsBroken; i++) {
|
||||
remove_random_stored_weapon(EQUIP_BOW, ITEM_BOWS);
|
||||
}
|
||||
string msg = (bowsBroken == 1)
|
||||
? "A resident's bow broke from wear."
|
||||
: bowsBroken + " bows broke from wear.";
|
||||
string msg = (bowsBroken == 1) ? "A resident's bow broke from wear." : bowsBroken + " bows broke from wear.";
|
||||
notify(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void attempt_resident_clothing_repairs() {
|
||||
if (residents_count <= 0) return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
|
||||
int threshold = get_storage_stack_limit() / 2;
|
||||
if (threshold < RESIDENT_CLOTHING_REPAIR_COST) {
|
||||
@@ -648,7 +702,8 @@ void attempt_resident_clothing_repairs() {
|
||||
best_count = down_count;
|
||||
}
|
||||
|
||||
if (best_item == -1) break;
|
||||
if (best_item == -1)
|
||||
break;
|
||||
|
||||
add_storage_count(best_item, -RESIDENT_CLOTHING_REPAIR_COST);
|
||||
repairs_done++;
|
||||
@@ -663,13 +718,14 @@ void attempt_resident_clothing_repairs() {
|
||||
}
|
||||
|
||||
if (repairs_done > 0 && x <= BASE_END) {
|
||||
string msg = (repairs_done == 1)
|
||||
? "A resident is mending clothing."
|
||||
: "Residents are mending clothing.";
|
||||
string msg = (repairs_done == 1) ? "A resident is mending clothing." : "Residents are mending clothing.";
|
||||
string[] materials;
|
||||
if (vines_used > 0) materials.insert_last(vines_used + " vines");
|
||||
if (skins_used > 0) materials.insert_last(skins_used + " skins");
|
||||
if (down_used > 0) materials.insert_last(down_used + " down");
|
||||
if (vines_used > 0)
|
||||
materials.insert_last(vines_used + " vines");
|
||||
if (skins_used > 0)
|
||||
materials.insert_last(skins_used + " skins");
|
||||
if (down_used > 0)
|
||||
materials.insert_last(down_used + " down");
|
||||
|
||||
if (materials.length() > 0) {
|
||||
msg += " Used ";
|
||||
@@ -693,35 +749,43 @@ void attempt_resident_clothing_repairs() {
|
||||
// Resident snare retrieval
|
||||
void attempt_resident_snare_retrieval() {
|
||||
// Only during daytime
|
||||
if (!is_daytime) return;
|
||||
if (!is_daytime)
|
||||
return;
|
||||
|
||||
// Need residents
|
||||
if (residents_count <= 0) return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
|
||||
// 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
|
||||
for (int i = int(world_snares.length()) - 1; i >= 0; i--) {
|
||||
WorldSnare@ snare = world_snares[i];
|
||||
if (!snare.has_catch) continue;
|
||||
if (!snare.active) continue;
|
||||
WorldSnare @snare = world_snares[i];
|
||||
if (!snare.has_catch)
|
||||
continue;
|
||||
if (!snare.active)
|
||||
continue;
|
||||
|
||||
// Each snare has a chance to be checked by a resident this hour
|
||||
if (random(1, 100) > check_chance) continue;
|
||||
if (random(1, 100) > check_chance)
|
||||
continue;
|
||||
|
||||
// Small chance the game escapes during retrieval (like normal)
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if storage has room for small game
|
||||
if (get_storage_count(ITEM_SMALL_GAME) >= get_storage_stack_limit()) continue;
|
||||
if (get_storage_count(ITEM_SMALL_GAME) >= get_storage_stack_limit())
|
||||
continue;
|
||||
|
||||
// Retrieve the game
|
||||
string game_type = snare.catch_type;
|
||||
@@ -746,26 +810,33 @@ void attempt_resident_snare_retrieval() {
|
||||
// Resident butchering - processes up to residents_count games per day (doubled when blessed)
|
||||
void attempt_resident_butchering() {
|
||||
// Need residents
|
||||
if (residents_count <= 0) return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
|
||||
// Need food in storage (same limitation as other resident tasks)
|
||||
if (!has_any_storage_food()) return;
|
||||
if (!has_any_storage_food())
|
||||
return;
|
||||
|
||||
// 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_SMALL_GAME) <= 0 && get_storage_count(ITEM_BOAR_CARCASSES) <= 0)
|
||||
return;
|
||||
|
||||
// Need a knife in storage
|
||||
if (get_storage_count(ITEM_KNIVES) <= 0) return;
|
||||
if (get_storage_count(ITEM_KNIVES) <= 0)
|
||||
return;
|
||||
|
||||
// Need a fire in base
|
||||
if (!has_burning_fire_in_base()) return;
|
||||
if (!has_burning_fire_in_base())
|
||||
return;
|
||||
|
||||
int attempts = residents_count * get_resident_effect_multiplier();
|
||||
int break_chance = get_resident_break_chance(RESIDENT_TOOL_BREAK_CHANCE);
|
||||
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;
|
||||
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 = "";
|
||||
@@ -804,11 +875,16 @@ void attempt_resident_butchering() {
|
||||
}
|
||||
|
||||
// Check storage capacity for outputs
|
||||
if (meat_yield > 0 && get_storage_count(ITEM_MEAT) + meat_yield > get_storage_stack_limit()) return;
|
||||
if (skins_yield > 0 && get_storage_count(ITEM_SKINS) + skins_yield > get_storage_stack_limit()) return;
|
||||
if (feathers_yield > 0 && get_storage_count(ITEM_FEATHERS) + feathers_yield > get_storage_stack_limit()) return;
|
||||
if (down_yield > 0 && get_storage_count(ITEM_DOWN) + down_yield > get_storage_stack_limit()) return;
|
||||
if (sinew_yield > 0 && get_storage_count(ITEM_SINEW) + sinew_yield > get_storage_stack_limit()) return;
|
||||
if (meat_yield > 0 && get_storage_count(ITEM_MEAT) + meat_yield > get_storage_stack_limit())
|
||||
return;
|
||||
if (skins_yield > 0 && get_storage_count(ITEM_SKINS) + skins_yield > get_storage_stack_limit())
|
||||
return;
|
||||
if (feathers_yield > 0 && get_storage_count(ITEM_FEATHERS) + feathers_yield > get_storage_stack_limit())
|
||||
return;
|
||||
if (down_yield > 0 && get_storage_count(ITEM_DOWN) + down_yield > get_storage_stack_limit())
|
||||
return;
|
||||
if (sinew_yield > 0 && get_storage_count(ITEM_SINEW) + sinew_yield > get_storage_stack_limit())
|
||||
return;
|
||||
|
||||
// Consume the game
|
||||
if (is_boar) {
|
||||
@@ -827,20 +903,30 @@ void attempt_resident_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);
|
||||
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");
|
||||
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) {
|
||||
@@ -862,16 +948,21 @@ void attempt_resident_butchering() {
|
||||
|
||||
void attempt_resident_collection() {
|
||||
// Only during daytime
|
||||
if (!is_daytime) return;
|
||||
if (!is_daytime)
|
||||
return;
|
||||
|
||||
// Need residents
|
||||
if (residents_count <= 0) return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
|
||||
// Need baskets in storage to enable collection
|
||||
if (get_storage_count(ITEM_REED_BASKETS) <= 0) return;
|
||||
if (get_storage_count(ITEM_REED_BASKETS) <= 0)
|
||||
return;
|
||||
|
||||
// Number of residents who can collect = min(residents, baskets)
|
||||
int active_collectors = (residents_count < get_storage_count(ITEM_REED_BASKETS)) ? residents_count : get_storage_count(ITEM_REED_BASKETS);
|
||||
int active_collectors = (residents_count < get_storage_count(ITEM_REED_BASKETS))
|
||||
? residents_count
|
||||
: get_storage_count(ITEM_REED_BASKETS);
|
||||
|
||||
// Each active collector has a 10% chance to collect something
|
||||
int baskets_broken = 0;
|
||||
@@ -884,7 +975,8 @@ void attempt_resident_collection() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (random(1, 100) > collection_chance) continue;
|
||||
if (random(1, 100) > collection_chance)
|
||||
continue;
|
||||
|
||||
// Determine what to collect (weighted random)
|
||||
// Sticks and vines more common, logs and stones less common
|
||||
@@ -919,9 +1011,7 @@ void attempt_resident_collection() {
|
||||
if (baskets_broken > 0) {
|
||||
add_storage_count(ITEM_REED_BASKETS, -baskets_broken);
|
||||
if (x <= BASE_END) {
|
||||
string msg = (baskets_broken == 1)
|
||||
? "A resident's basket broke."
|
||||
: baskets_broken + " baskets broke.";
|
||||
string msg = (baskets_broken == 1) ? "A resident's basket broke." : baskets_broken + " baskets broke.";
|
||||
speak_with_history(msg, true);
|
||||
}
|
||||
}
|
||||
@@ -930,19 +1020,25 @@ void attempt_resident_collection() {
|
||||
// Resident foraging - produces baskets of fruits and nuts from reed baskets
|
||||
void attempt_resident_foraging() {
|
||||
// Only during daytime
|
||||
if (!is_daytime) return;
|
||||
if (!is_daytime)
|
||||
return;
|
||||
|
||||
// Need residents
|
||||
if (residents_count <= 0) return;
|
||||
if (residents_count <= 0)
|
||||
return;
|
||||
|
||||
// Need reed baskets in storage
|
||||
if (get_storage_count(ITEM_REED_BASKETS) <= 0) return;
|
||||
if (get_storage_count(ITEM_REED_BASKETS) <= 0)
|
||||
return;
|
||||
|
||||
// Check if storage has room for basket food
|
||||
if (get_storage_count(ITEM_BASKET_FOOD) >= get_storage_stack_limit()) return;
|
||||
if (get_storage_count(ITEM_BASKET_FOOD) >= get_storage_stack_limit())
|
||||
return;
|
||||
|
||||
// Number of residents who can forage = min(residents, baskets)
|
||||
int active_foragers = (residents_count < get_storage_count(ITEM_REED_BASKETS)) ? residents_count : get_storage_count(ITEM_REED_BASKETS);
|
||||
int active_foragers = (residents_count < get_storage_count(ITEM_REED_BASKETS))
|
||||
? residents_count
|
||||
: get_storage_count(ITEM_REED_BASKETS);
|
||||
|
||||
int baskets_produced = 0;
|
||||
int baskets_broken = 0;
|
||||
@@ -957,10 +1053,12 @@ void attempt_resident_foraging() {
|
||||
}
|
||||
|
||||
// Check if foraging succeeds
|
||||
if (random(1, 100) > forage_chance) continue;
|
||||
if (random(1, 100) > forage_chance)
|
||||
continue;
|
||||
|
||||
// Check storage capacity
|
||||
if (get_storage_count(ITEM_BASKET_FOOD) >= get_storage_stack_limit()) break;
|
||||
if (get_storage_count(ITEM_BASKET_FOOD) >= get_storage_stack_limit())
|
||||
break;
|
||||
|
||||
// Consume a reed basket and produce a basket of fruits and nuts
|
||||
add_storage_count(ITEM_REED_BASKETS, -1);
|
||||
@@ -972,8 +1070,7 @@ void attempt_resident_foraging() {
|
||||
if (baskets_broken > 0) {
|
||||
add_storage_count(ITEM_REED_BASKETS, -baskets_broken);
|
||||
if (x <= BASE_END) {
|
||||
string msg = (baskets_broken == 1)
|
||||
? "A resident's basket broke while foraging."
|
||||
string msg = (baskets_broken == 1) ? "A resident's basket broke while foraging."
|
||||
: baskets_broken + " baskets broke while foraging.";
|
||||
speak_with_history(msg, true);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ void reset_adventure_combat_state() {
|
||||
last_sling_stage = -1;
|
||||
}
|
||||
|
||||
void update_weapon_range_audio_with_listener(int listener_x, int creature_pos, bool &inout was_in_range) {
|
||||
void update_weapon_range_audio_with_listener(int listener_x, int creature_pos, bool& inout was_in_range) {
|
||||
int range = get_current_weapon_range();
|
||||
bool in_range = (range >= 0) && (abs(creature_pos - listener_x) <= range);
|
||||
if (in_range && !was_in_range) {
|
||||
@@ -37,24 +37,23 @@ void adventure_start_bow_shot_audio(int listener_x, int start_x, int end_x, int
|
||||
bow_shot_end_x = end_x;
|
||||
bow_shot_hit_x = hit_x;
|
||||
bow_shot_duration_ms = duration_ms;
|
||||
if (bow_shot_duration_ms < 1) bow_shot_duration_ms = 1;
|
||||
if (bow_shot_duration_ms < 1)
|
||||
bow_shot_duration_ms = 1;
|
||||
|
||||
bow_shot_sound_handle = play_1d_with_volume_step(
|
||||
"sounds/weapons/arrow_flies.ogg",
|
||||
listener_x,
|
||||
bow_shot_start_x,
|
||||
false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP
|
||||
);
|
||||
bow_shot_sound_handle = play_1d_with_volume_step("sounds/weapons/arrow_flies.ogg", listener_x, bow_shot_start_x,
|
||||
false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
void adventure_update_bow_shot(int listener_x) {
|
||||
if (!bow_shot_active) return;
|
||||
if (bow_shot_duration_ms < 1) bow_shot_duration_ms = 1;
|
||||
if (!bow_shot_active)
|
||||
return;
|
||||
if (bow_shot_duration_ms < 1)
|
||||
bow_shot_duration_ms = 1;
|
||||
|
||||
int elapsed = bow_shot_timer.elapsed;
|
||||
float progress = float(elapsed) / float(bow_shot_duration_ms);
|
||||
if (progress > 1.0f) progress = 1.0f;
|
||||
if (progress > 1.0f)
|
||||
progress = 1.0f;
|
||||
|
||||
int travel = int(float(bow_shot_end_x - bow_shot_start_x) * progress);
|
||||
int current_pos = bow_shot_start_x + travel;
|
||||
@@ -68,13 +67,8 @@ void adventure_update_bow_shot(int listener_x) {
|
||||
stop_bow_shot_audio();
|
||||
adventure_arrow_recover_pending = false;
|
||||
if (hit_x >= 0) {
|
||||
play_1d_with_volume_step(
|
||||
"sounds/weapons/arrow_hit.ogg",
|
||||
listener_x,
|
||||
hit_x,
|
||||
false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP
|
||||
);
|
||||
play_1d_with_volume_step("sounds/weapons/arrow_hit.ogg", listener_x, hit_x, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
}
|
||||
if (recover_pending) {
|
||||
add_personal_count(ITEM_ARROWS, 1);
|
||||
@@ -82,7 +76,7 @@ void adventure_update_bow_shot(int listener_x) {
|
||||
}
|
||||
}
|
||||
|
||||
void adventure_release_bow_attack(int player_x, int player_facing, AdventureRangedReleaseCallback@ ranged_callback) {
|
||||
void adventure_release_bow_attack(int player_x, int player_facing, AdventureRangedReleaseCallback @ranged_callback) {
|
||||
if (get_personal_count(ITEM_ARROWS) <= 0) {
|
||||
speak_ammo_blocked("No arrows.");
|
||||
return;
|
||||
@@ -99,23 +93,23 @@ void adventure_release_bow_attack(int player_x, int player_facing, AdventureRang
|
||||
target_x = ranged_callback(player_x, search_direction, BOW_RANGE, ADVENTURE_WEAPON_BOW, damage);
|
||||
}
|
||||
|
||||
int end_x = (target_x != -1)
|
||||
? target_x
|
||||
: (player_x + (search_direction * (BOW_RANGE + BOW_MISS_EXTRA_TILES)));
|
||||
int end_x = (target_x != -1) ? target_x : (player_x + (search_direction * (BOW_RANGE + BOW_MISS_EXTRA_TILES)));
|
||||
|
||||
int duration_ms = ARROW_FLIES_DURATION_MS;
|
||||
if (target_x != -1) {
|
||||
int distance = abs(target_x - player_x);
|
||||
if (distance < 1) distance = 1;
|
||||
if (distance < 1)
|
||||
distance = 1;
|
||||
duration_ms = int(float(ARROW_FLIES_DURATION_MS) * (float(distance) / float(BOW_RANGE)));
|
||||
if (duration_ms < 1) duration_ms = 1;
|
||||
if (duration_ms < 1)
|
||||
duration_ms = 1;
|
||||
}
|
||||
|
||||
adventure_arrow_recover_pending = (random(1, 100) <= 25);
|
||||
adventure_start_bow_shot_audio(player_x, player_x, end_x, target_x, duration_ms);
|
||||
}
|
||||
|
||||
void adventure_release_sling_attack(int player_x, int player_facing, AdventureRangedReleaseCallback@ ranged_callback) {
|
||||
void adventure_release_sling_attack(int player_x, int player_facing, AdventureRangedReleaseCallback @ranged_callback) {
|
||||
add_personal_count(ITEM_STONES, -1);
|
||||
|
||||
int elapsed = sling_charge_timer.elapsed;
|
||||
@@ -124,7 +118,6 @@ void adventure_release_sling_attack(int player_x, int player_facing, AdventureRa
|
||||
int stage = time_in_cycle / 500; // 0=low, 1=in-range, 2=high
|
||||
|
||||
if (stage != 1) {
|
||||
speak_with_history("Stone missed.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -138,9 +131,9 @@ void adventure_release_sling_attack(int player_x, int player_facing, AdventureRa
|
||||
}
|
||||
|
||||
if (target_x == -1) {
|
||||
speak_with_history("Stone missed.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ void run_adventure_menu(int player_x) {
|
||||
}
|
||||
|
||||
string terrain = get_terrain_at_position(player_x);
|
||||
MountainRange@ mountain = get_mountain_at(player_x);
|
||||
MountainRange @mountain = get_mountain_at(player_x);
|
||||
|
||||
// Check available adventures based on terrain
|
||||
string[] options;
|
||||
@@ -62,14 +62,16 @@ void run_adventure_menu(int player_x) {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= options.length()) selection = 0;
|
||||
if (selection >= options.length())
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = options.length() - 1;
|
||||
if (selection < 0)
|
||||
selection = options.length() - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
|
||||
+131
-69
@@ -27,7 +27,7 @@ class HideoutBandit {
|
||||
timer attackTimer;
|
||||
int moveInterval;
|
||||
|
||||
HideoutBandit(int pos, const string&in alert, const string&in weapon, int interval) {
|
||||
HideoutBandit(int pos, const string& in alert, const string& in weapon, int interval) {
|
||||
position = pos;
|
||||
health = BANDIT_HEALTH;
|
||||
alertSound = alert;
|
||||
@@ -40,7 +40,7 @@ class HideoutBandit {
|
||||
}
|
||||
}
|
||||
|
||||
HideoutBandit@[] hideoutBandits;
|
||||
HideoutBandit @[] hideoutBandits;
|
||||
string[] hideoutTerrain;
|
||||
int hideoutPlayerX = 0;
|
||||
int hideoutPlayerFacing = 1; // 0 = west, 1 = east
|
||||
@@ -74,8 +74,10 @@ void restart_hideout_adventure_timers() {
|
||||
|
||||
string pick_hideout_terrain() {
|
||||
int roll = random(0, 2);
|
||||
if (roll == 0) return "grass";
|
||||
if (roll == 1) return "gravel";
|
||||
if (roll == 0)
|
||||
return "grass";
|
||||
if (roll == 1)
|
||||
return "gravel";
|
||||
return "stone";
|
||||
}
|
||||
|
||||
@@ -96,30 +98,35 @@ void build_hideout_terrain() {
|
||||
}
|
||||
|
||||
string get_hideout_terrain_at(int pos) {
|
||||
if (pos < 0 || pos >= int(hideoutTerrain.length())) return "grass";
|
||||
if (pos < 0 || pos >= int(hideoutTerrain.length()))
|
||||
return "grass";
|
||||
string terrain = hideoutTerrain[pos];
|
||||
if (terrain == "") return "grass";
|
||||
if (terrain == "")
|
||||
return "grass";
|
||||
return terrain;
|
||||
}
|
||||
|
||||
string get_hideout_footstep_sound(int pos) {
|
||||
string terrain = get_hideout_terrain_at(pos);
|
||||
if (terrain == "stone") return "sounds/terrain/stone.ogg";
|
||||
if (terrain == "gravel") return "sounds/terrain/gravel.ogg";
|
||||
if (terrain == "stone")
|
||||
return "sounds/terrain/stone.ogg";
|
||||
if (terrain == "gravel")
|
||||
return "sounds/terrain/gravel.ogg";
|
||||
return "sounds/terrain/grass.ogg";
|
||||
}
|
||||
|
||||
void play_hideout_player_footstep() {
|
||||
string soundFile = get_hideout_footstep_sound(hideoutPlayerX);
|
||||
if (file_exists(soundFile)) {
|
||||
if (audio_asset_exists(soundFile)) {
|
||||
p.play_stationary(soundFile, false);
|
||||
}
|
||||
}
|
||||
|
||||
void play_hideout_positional_footstep(int listenerX, int stepX, int maxDistance, float volumeStep) {
|
||||
if (abs(stepX - listenerX) > maxDistance) return;
|
||||
if (abs(stepX - listenerX) > maxDistance)
|
||||
return;
|
||||
string soundFile = get_hideout_footstep_sound(stepX);
|
||||
if (file_exists(soundFile)) {
|
||||
if (audio_asset_exists(soundFile)) {
|
||||
play_1d_with_volume_step(soundFile, listenerX, stepX, false, volumeStep);
|
||||
}
|
||||
}
|
||||
@@ -135,7 +142,7 @@ void clear_hideout_bandits() {
|
||||
hideoutBandits.resize(0);
|
||||
}
|
||||
|
||||
HideoutBandit@ get_hideout_bandit_at(int pos) {
|
||||
HideoutBandit @get_hideout_bandit_at(int pos) {
|
||||
for (uint i = 0; i < hideoutBandits.length(); i++) {
|
||||
if (hideoutBandits[i].position == pos) {
|
||||
return @hideoutBandits[i];
|
||||
@@ -144,7 +151,8 @@ HideoutBandit@ get_hideout_bandit_at(int pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
bool pet_find_hideout_target(int originPos, int referencePos, int &out targetPos, string &out targetLabel, int &out targetKind) {
|
||||
bool pet_find_hideout_target(int originPos, int referencePos, int& out targetPos, string& out targetLabel,
|
||||
int& out targetKind) {
|
||||
int bestDistance = PET_RANGE + 1;
|
||||
targetPos = -1;
|
||||
targetLabel = "";
|
||||
@@ -152,7 +160,8 @@ bool pet_find_hideout_target(int originPos, int referencePos, int &out targetPos
|
||||
|
||||
for (uint i = 0; i < hideoutBandits.length(); i++) {
|
||||
int distanceToOrigin = abs(hideoutBandits[i].position - originPos);
|
||||
if (distanceToOrigin > PET_RANGE) continue;
|
||||
if (distanceToOrigin > PET_RANGE)
|
||||
continue;
|
||||
int distance = abs(hideoutBandits[i].position - referencePos);
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
@@ -166,19 +175,24 @@ bool pet_find_hideout_target(int originPos, int referencePos, int &out targetPos
|
||||
}
|
||||
|
||||
bool pet_damage_hideout_target(int targetKind, int targetPos, int damage) {
|
||||
if (targetKind != 0) return false;
|
||||
if (targetKind != 0)
|
||||
return false;
|
||||
return damage_hideout_bandit_at(targetPos, damage);
|
||||
}
|
||||
|
||||
int clamp_hideout_spawn_start(int startX) {
|
||||
if (startX < 0) return 0;
|
||||
if (startX >= BANDIT_HIDEOUT_MAP_SIZE) return BANDIT_HIDEOUT_MAP_SIZE - 1;
|
||||
if (startX < 0)
|
||||
return 0;
|
||||
if (startX >= BANDIT_HIDEOUT_MAP_SIZE)
|
||||
return BANDIT_HIDEOUT_MAP_SIZE - 1;
|
||||
return startX;
|
||||
}
|
||||
|
||||
int clamp_hideout_spawn_end(int endX) {
|
||||
if (endX < 0) return 0;
|
||||
if (endX >= BANDIT_HIDEOUT_MAP_SIZE) return BANDIT_HIDEOUT_MAP_SIZE - 1;
|
||||
if (endX < 0)
|
||||
return 0;
|
||||
if (endX >= BANDIT_HIDEOUT_MAP_SIZE)
|
||||
return BANDIT_HIDEOUT_MAP_SIZE - 1;
|
||||
return endX;
|
||||
}
|
||||
|
||||
@@ -194,8 +208,10 @@ int pick_hideout_spawn_position(int startX, int endX) {
|
||||
int spawnX = -1;
|
||||
for (int attempt = 0; attempt < 20; attempt++) {
|
||||
int candidate = random(startClamp, endClamp);
|
||||
if (candidate == hideoutPlayerX) continue;
|
||||
if (get_hideout_bandit_at(candidate) != null) continue;
|
||||
if (candidate == hideoutPlayerX)
|
||||
continue;
|
||||
if (get_hideout_bandit_at(candidate) != null)
|
||||
continue;
|
||||
spawnX = candidate;
|
||||
break;
|
||||
}
|
||||
@@ -208,13 +224,15 @@ int pick_hideout_spawn_position(int startX, int endX) {
|
||||
void spawn_hideout_bandit_in_range(int startX, int endX) {
|
||||
int spawnX = pick_hideout_spawn_position(startX, endX);
|
||||
string alertSound = pick_invader_alert_sound("bandit");
|
||||
if (alertSound == "") alertSound = "sounds/enemies/bandit1.ogg";
|
||||
if (alertSound == "")
|
||||
alertSound = "sounds/enemies/bandit1.ogg";
|
||||
string weaponType = (random(0, 1) == 0) ? "spear" : "axe";
|
||||
int moveInterval = random(BANDIT_MOVE_INTERVAL_MIN, BANDIT_MOVE_INTERVAL_MAX);
|
||||
|
||||
HideoutBandit@ bandit = HideoutBandit(spawnX, alertSound, weaponType, moveInterval);
|
||||
HideoutBandit @bandit = HideoutBandit(spawnX, alertSound, weaponType, moveInterval);
|
||||
hideoutBandits.insert_last(bandit);
|
||||
bandit.soundHandle = play_1d_with_volume_step(bandit.alertSound, hideoutPlayerX, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
|
||||
bandit.soundHandle =
|
||||
play_1d_with_volume_step(bandit.alertSound, hideoutPlayerX, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
void spawn_hideout_bandits_initial() {
|
||||
@@ -228,7 +246,8 @@ void spawn_hideout_bandits_initial() {
|
||||
void respawn_hideout_bandit() {
|
||||
int startSpawnStart = 0;
|
||||
int startSpawnEnd = BANDIT_HIDEOUT_START_SPAWN_RANGE - 1;
|
||||
if (startSpawnEnd > hideoutBaseX) startSpawnEnd = hideoutBaseX;
|
||||
if (startSpawnEnd > hideoutBaseX)
|
||||
startSpawnEnd = hideoutBaseX;
|
||||
|
||||
int baseSpawnStart = hideoutBaseX - (BANDIT_HIDEOUT_BASE_SPAWN_RANGE - 1);
|
||||
int baseSpawnEnd = hideoutBaseX;
|
||||
@@ -250,8 +269,10 @@ void init_bandit_hideout_adventure() {
|
||||
hideoutPlayerJumping = false;
|
||||
|
||||
int barricadeBase = current_day * BANDIT_HIDEOUT_BARRICADE_HP_PER_DAY;
|
||||
if (barricadeBase < BANDIT_HIDEOUT_BARRICADE_HP_PER_DAY) barricadeBase = BANDIT_HIDEOUT_BARRICADE_HP_PER_DAY;
|
||||
if (barricadeBase > BANDIT_HIDEOUT_BARRICADE_HP_MAX) barricadeBase = BANDIT_HIDEOUT_BARRICADE_HP_MAX;
|
||||
if (barricadeBase < BANDIT_HIDEOUT_BARRICADE_HP_PER_DAY)
|
||||
barricadeBase = BANDIT_HIDEOUT_BARRICADE_HP_PER_DAY;
|
||||
if (barricadeBase > BANDIT_HIDEOUT_BARRICADE_HP_MAX)
|
||||
barricadeBase = BANDIT_HIDEOUT_BARRICADE_HP_MAX;
|
||||
hideoutBarricadeMax = barricadeBase;
|
||||
hideoutBarricadeHealth = barricadeBase;
|
||||
|
||||
@@ -331,9 +352,13 @@ void run_bandit_hideout_adventure() {
|
||||
|
||||
if (key_pressed(KEY_X)) {
|
||||
int distanceToBase = hideoutBaseX - hideoutPlayerX;
|
||||
if (distanceToBase < 0) distanceToBase = 0;
|
||||
if (distanceToBase < 0)
|
||||
distanceToBase = 0;
|
||||
string terrain = get_hideout_terrain_at(hideoutPlayerX);
|
||||
speak_with_history("x " + hideoutPlayerX + ", terrain " + terrain + ". Base " + distanceToBase + " tiles east. Barricade " + hideoutBarricadeHealth + " of " + hideoutBarricadeMax + ".", true);
|
||||
speak_with_history("x " + hideoutPlayerX + ", terrain " + terrain + ". Base " + distanceToBase +
|
||||
" tiles east. Barricade " + hideoutBarricadeHealth + " of " + hideoutBarricadeMax +
|
||||
".",
|
||||
true);
|
||||
}
|
||||
|
||||
handle_hideout_player_movement();
|
||||
@@ -381,12 +406,14 @@ void handle_hideout_player_movement() {
|
||||
hideoutPlayerFacing = 0;
|
||||
hideoutPlayerX--;
|
||||
hideoutWalkTimer.restart();
|
||||
if (player_health > 0 && !hideoutPlayerJumping) play_hideout_player_footstep();
|
||||
if (player_health > 0 && !hideoutPlayerJumping)
|
||||
play_hideout_player_footstep();
|
||||
} else if (key_down(KEY_RIGHT) && hideoutPlayerX < hideoutBaseX) {
|
||||
hideoutPlayerFacing = 1;
|
||||
hideoutPlayerX++;
|
||||
hideoutWalkTimer.restart();
|
||||
if (player_health > 0 && !hideoutPlayerJumping) play_hideout_player_footstep();
|
||||
if (player_health > 0 && !hideoutPlayerJumping)
|
||||
play_hideout_player_footstep();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,13 +471,17 @@ void handle_hideout_player_actions() {
|
||||
}
|
||||
|
||||
if (!bow_equipped && !bow_drawing && !sling_equipped && !sling_charging) {
|
||||
if (fishing_pole_equipped) return;
|
||||
if (fishing_pole_equipped)
|
||||
return;
|
||||
int weaponType = get_hideout_melee_weapon_type();
|
||||
if (weaponType == -1) return;
|
||||
if (weaponType == -1)
|
||||
return;
|
||||
|
||||
int attackCooldown = 1000;
|
||||
if (weaponType == ADVENTURE_WEAPON_SPEAR) attackCooldown = 800;
|
||||
if (weaponType == ADVENTURE_WEAPON_AXE) attackCooldown = 1600;
|
||||
if (weaponType == ADVENTURE_WEAPON_SPEAR)
|
||||
attackCooldown = 800;
|
||||
if (weaponType == ADVENTURE_WEAPON_AXE)
|
||||
attackCooldown = 1600;
|
||||
|
||||
if (ctrlDown && hideoutAttackTimer.elapsed > attackCooldown) {
|
||||
hideoutAttackTimer.restart();
|
||||
@@ -506,8 +537,10 @@ void perform_hideout_search() {
|
||||
}
|
||||
|
||||
int get_hideout_melee_weapon_type() {
|
||||
if (spear_equipped) return ADVENTURE_WEAPON_SPEAR;
|
||||
if (axe_equipped) return ADVENTURE_WEAPON_AXE;
|
||||
if (spear_equipped)
|
||||
return ADVENTURE_WEAPON_SPEAR;
|
||||
if (axe_equipped)
|
||||
return ADVENTURE_WEAPON_AXE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -550,18 +583,23 @@ bool hideout_melee_hit(int weaponType) {
|
||||
}
|
||||
|
||||
bool apply_hideout_barricade_damage(int damage) {
|
||||
if (damage <= 0) return false;
|
||||
if (hideoutBarricadeHealth <= 0) return false;
|
||||
if (damage <= 0)
|
||||
return false;
|
||||
if (hideoutBarricadeHealth <= 0)
|
||||
return false;
|
||||
hideoutBarricadeHealth -= damage;
|
||||
if (hideoutBarricadeHealth < 0) hideoutBarricadeHealth = 0;
|
||||
play_1d_with_volume_step("sounds/weapons/axe_hit.ogg", hideoutPlayerX, hideoutBaseX, false, BANDIT_SOUND_VOLUME_STEP);
|
||||
if (hideoutBarricadeHealth < 0)
|
||||
hideoutBarricadeHealth = 0;
|
||||
play_1d_with_volume_step("sounds/weapons/axe_hit.ogg", hideoutPlayerX, hideoutBaseX, false,
|
||||
BANDIT_SOUND_VOLUME_STEP);
|
||||
return true;
|
||||
}
|
||||
|
||||
int find_hideout_ranged_target(int playerX, int direction, int range) {
|
||||
for (int dist = 1; dist <= range; dist++) {
|
||||
int checkX = playerX + (dist * direction);
|
||||
if (checkX < 0 || checkX >= BANDIT_HIDEOUT_MAP_SIZE) break;
|
||||
if (checkX < 0 || checkX >= BANDIT_HIDEOUT_MAP_SIZE)
|
||||
break;
|
||||
|
||||
if (get_hideout_bandit_at(checkX) != null) {
|
||||
return checkX;
|
||||
@@ -576,7 +614,8 @@ int find_hideout_ranged_target(int playerX, int direction, int range) {
|
||||
|
||||
int bandit_hideout_ranged_attack(int playerX, int direction, int range, int weaponType, int damage) {
|
||||
int targetX = find_hideout_ranged_target(playerX, direction, range);
|
||||
if (targetX == -1) return -1;
|
||||
if (targetX == -1)
|
||||
return -1;
|
||||
|
||||
if (targetX == hideoutBaseX) {
|
||||
apply_hideout_barricade_damage(damage);
|
||||
@@ -602,7 +641,8 @@ bool damage_hideout_bandit_at(int pos, int damage) {
|
||||
if (hideoutBandits[i].inWeaponRange) {
|
||||
play_weapon_range_sound("sounds/enemies/exit_range.ogg", hideoutBandits[i].position);
|
||||
}
|
||||
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", hideoutBandits[i].alertSound, hideoutPlayerX, pos, BANDIT_SOUND_VOLUME_STEP);
|
||||
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", hideoutBandits[i].alertSound,
|
||||
hideoutPlayerX, pos, BANDIT_SOUND_VOLUME_STEP);
|
||||
hideoutBandits.remove_at(i);
|
||||
hideoutBanditsKilled++;
|
||||
respawn_hideout_bandit();
|
||||
@@ -616,37 +656,46 @@ bool damage_hideout_bandit_at(int pos, int damage) {
|
||||
void update_hideout_player_jump() {
|
||||
if (hideoutPlayerJumping && hideoutJumpTimer.elapsed > 850) {
|
||||
hideoutPlayerJumping = false;
|
||||
if (player_health > 0) play_hideout_player_footstep();
|
||||
if (player_health > 0)
|
||||
play_hideout_player_footstep();
|
||||
}
|
||||
}
|
||||
|
||||
bool try_hideout_bandit_attack_player(HideoutBandit@ bandit) {
|
||||
if (player_health <= 0) return false;
|
||||
if (abs(bandit.position - hideoutPlayerX) > 1) return false;
|
||||
if (bandit.attackTimer.elapsed < BANDIT_ATTACK_INTERVAL) return false;
|
||||
bool try_hideout_bandit_attack_player(HideoutBandit @bandit) {
|
||||
if (player_health <= 0)
|
||||
return false;
|
||||
if (abs(bandit.position - hideoutPlayerX) > 1)
|
||||
return false;
|
||||
if (bandit.attackTimer.elapsed < BANDIT_ATTACK_INTERVAL)
|
||||
return false;
|
||||
|
||||
bandit.attackTimer.restart();
|
||||
|
||||
if (bandit.weaponType == "spear") {
|
||||
play_creature_attack_sound("sounds/weapons/spear_swing.ogg", hideoutPlayerX, bandit.position, BANDIT_SOUND_VOLUME_STEP);
|
||||
play_creature_attack_sound("sounds/weapons/spear_swing.ogg", hideoutPlayerX, bandit.position,
|
||||
BANDIT_SOUND_VOLUME_STEP);
|
||||
} else {
|
||||
play_creature_attack_sound("sounds/weapons/axe_swing.ogg", hideoutPlayerX, bandit.position, BANDIT_SOUND_VOLUME_STEP);
|
||||
play_creature_attack_sound("sounds/weapons/axe_swing.ogg", hideoutPlayerX, bandit.position,
|
||||
BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
int damage = random(BANDIT_DAMAGE_MIN, BANDIT_DAMAGE_MAX);
|
||||
player_health -= damage;
|
||||
if (player_health < 0) player_health = 0;
|
||||
if (player_health < 0)
|
||||
player_health = 0;
|
||||
|
||||
if (bandit.weaponType == "spear") {
|
||||
play_creature_attack_sound("sounds/weapons/spear_hit.ogg", hideoutPlayerX, bandit.position, BANDIT_SOUND_VOLUME_STEP);
|
||||
play_creature_attack_sound("sounds/weapons/spear_hit.ogg", hideoutPlayerX, bandit.position,
|
||||
BANDIT_SOUND_VOLUME_STEP);
|
||||
} else {
|
||||
play_creature_attack_sound("sounds/weapons/axe_hit.ogg", hideoutPlayerX, bandit.position, BANDIT_SOUND_VOLUME_STEP);
|
||||
play_creature_attack_sound("sounds/weapons/axe_hit.ogg", hideoutPlayerX, bandit.position,
|
||||
BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
play_player_damage_sound();
|
||||
return true;
|
||||
}
|
||||
|
||||
void update_hideout_bandit_audio(HideoutBandit@ bandit) {
|
||||
void update_hideout_bandit_audio(HideoutBandit @bandit) {
|
||||
if (bandit.soundHandle != -1 && p.sound_is_active(bandit.soundHandle)) {
|
||||
p.update_sound_1d(bandit.soundHandle, bandit.position);
|
||||
return;
|
||||
@@ -654,10 +703,11 @@ void update_hideout_bandit_audio(HideoutBandit@ bandit) {
|
||||
if (bandit.soundHandle != -1) {
|
||||
p.destroy_sound(bandit.soundHandle);
|
||||
}
|
||||
bandit.soundHandle = play_1d_with_volume_step(bandit.alertSound, hideoutPlayerX, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
|
||||
bandit.soundHandle =
|
||||
play_1d_with_volume_step(bandit.alertSound, hideoutPlayerX, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
void update_hideout_bandit(HideoutBandit@ bandit) {
|
||||
void update_hideout_bandit(HideoutBandit @bandit) {
|
||||
update_weapon_range_audio_with_listener(hideoutPlayerX, bandit.position, bandit.inWeaponRange);
|
||||
|
||||
if (try_hideout_bandit_attack_player(bandit)) {
|
||||
@@ -672,15 +722,18 @@ void update_hideout_bandit(HideoutBandit@ bandit) {
|
||||
bandit.moveTimer.restart();
|
||||
|
||||
int direction = 0;
|
||||
if (hideoutPlayerX > bandit.position) direction = 1;
|
||||
else if (hideoutPlayerX < bandit.position) direction = -1;
|
||||
if (hideoutPlayerX > bandit.position)
|
||||
direction = 1;
|
||||
else if (hideoutPlayerX < bandit.position)
|
||||
direction = -1;
|
||||
|
||||
if (direction != 0) {
|
||||
int targetX = bandit.position + direction;
|
||||
if (targetX >= 0 && targetX < BANDIT_HIDEOUT_MAP_SIZE) {
|
||||
if (get_hideout_bandit_at(targetX) == null) {
|
||||
bandit.position = targetX;
|
||||
play_hideout_positional_footstep(hideoutPlayerX, bandit.position, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
|
||||
play_hideout_positional_footstep(hideoutPlayerX, bandit.position, BANDIT_FOOTSTEP_MAX_DISTANCE,
|
||||
BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -695,12 +748,16 @@ void update_hideout_bandits() {
|
||||
}
|
||||
|
||||
int add_hideout_storage_item(int itemType, int amount) {
|
||||
if (amount <= 0) return 0;
|
||||
if (amount <= 0)
|
||||
return 0;
|
||||
int capacity = get_storage_stack_limit() - get_storage_count(itemType);
|
||||
if (capacity <= 0) return 0;
|
||||
if (capacity <= 0)
|
||||
return 0;
|
||||
int addedAmount = amount;
|
||||
if (addedAmount > capacity) addedAmount = capacity;
|
||||
if (addedAmount <= 0) return 0;
|
||||
if (addedAmount > capacity)
|
||||
addedAmount = capacity;
|
||||
if (addedAmount <= 0)
|
||||
return 0;
|
||||
|
||||
add_storage_count(itemType, addedAmount);
|
||||
|
||||
@@ -728,8 +785,10 @@ void give_bandit_hideout_rewards() {
|
||||
|
||||
if (world_altars.length() > 0) {
|
||||
double favorReward = BANDIT_HIDEOUT_BASE_FAVOR + (hideoutBanditsKilled * BANDIT_HIDEOUT_FAVOR_PER_KILL);
|
||||
if (favorReward > BANDIT_HIDEOUT_FAVOR_MAX) favorReward = BANDIT_HIDEOUT_FAVOR_MAX;
|
||||
if (favorReward < BANDIT_HIDEOUT_BASE_FAVOR) favorReward = BANDIT_HIDEOUT_BASE_FAVOR;
|
||||
if (favorReward > BANDIT_HIDEOUT_FAVOR_MAX)
|
||||
favorReward = BANDIT_HIDEOUT_FAVOR_MAX;
|
||||
if (favorReward < BANDIT_HIDEOUT_BASE_FAVOR)
|
||||
favorReward = BANDIT_HIDEOUT_BASE_FAVOR;
|
||||
favor += favorReward;
|
||||
rewards.insert_last("Favor awarded: " + format_favor(favorReward) + ".");
|
||||
} else {
|
||||
@@ -745,9 +804,11 @@ void give_bandit_hideout_rewards() {
|
||||
bool anyItems = false;
|
||||
for (int itemType = 0; itemType < ITEM_COUNT; itemType++) {
|
||||
int roll = random(0, BANDIT_HIDEOUT_ITEM_REWARD_MAX);
|
||||
if (roll <= 0) continue;
|
||||
if (roll <= 0)
|
||||
continue;
|
||||
int addedAmount = add_hideout_storage_item(itemType, roll);
|
||||
if (addedAmount <= 0) continue;
|
||||
if (addedAmount <= 0)
|
||||
continue;
|
||||
rewards.insert_last(get_item_display_name(itemType) + ": +" + addedAmount + ".");
|
||||
anyItems = true;
|
||||
}
|
||||
@@ -785,7 +846,8 @@ void give_bandit_hideout_rewards() {
|
||||
int survivorRoll = random(1, 100);
|
||||
if (survivorRoll <= 50) {
|
||||
residents_count += 1;
|
||||
if (residents_count > MAX_RESIDENTS) residents_count = MAX_RESIDENTS;
|
||||
if (residents_count > MAX_RESIDENTS)
|
||||
residents_count = MAX_RESIDENTS;
|
||||
rewards.insert_last("");
|
||||
rewards.insert_last("A survivor joins your base.");
|
||||
} else {
|
||||
|
||||
@@ -168,7 +168,9 @@ void run_unicorn_adventure() {
|
||||
// Coordinates
|
||||
if (key_pressed(KEY_X)) {
|
||||
string facing_dir = (unicorn.facing == 1) ? "east" : "west";
|
||||
string terrain = (player_arena_x >= BRIDGE_START && player_arena_x <= BRIDGE_END && !bridge_collapsed) ? "wood" : "grass";
|
||||
string terrain = (player_arena_x >= BRIDGE_START && player_arena_x <= BRIDGE_END && !bridge_collapsed)
|
||||
? "wood"
|
||||
: "grass";
|
||||
speak_with_history("x " + player_arena_x + ", terrain " + terrain + ". Unicorn facing " + facing_dir, true);
|
||||
}
|
||||
|
||||
@@ -236,13 +238,15 @@ void handle_player_movement() {
|
||||
player_arena_x--;
|
||||
arena_walk_timer.restart();
|
||||
check_player_chasm_fall();
|
||||
if (player_health > 0) play_footstep_sound();
|
||||
if (player_health > 0)
|
||||
play_footstep_sound();
|
||||
} else if (key_down(KEY_RIGHT) && player_arena_x < UNICORN_ARENA_SIZE - 1) {
|
||||
player_arena_facing = 1;
|
||||
player_arena_x++;
|
||||
arena_walk_timer.restart();
|
||||
check_player_chasm_fall();
|
||||
if (player_health > 0) play_footstep_sound();
|
||||
if (player_health > 0)
|
||||
play_footstep_sound();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,8 +287,10 @@ void check_player_chasm_fall() {
|
||||
|
||||
float height_remaining = float(total_fall - feet_fallen);
|
||||
float pitch_percent = 50.0 + (50.0 * (height_remaining / float(total_fall)));
|
||||
if (pitch_percent < 50.0) pitch_percent = 50.0;
|
||||
if (pitch_percent > 100.0) pitch_percent = 100.0;
|
||||
if (pitch_percent < 50.0)
|
||||
pitch_percent = 50.0;
|
||||
if (pitch_percent > 100.0)
|
||||
pitch_percent = 100.0;
|
||||
|
||||
fall_handle = p.play_stationary_extended("sounds/actions/falling.ogg", true, 0, 0, 0, pitch_percent);
|
||||
}
|
||||
@@ -309,7 +315,8 @@ void update_player_jump() {
|
||||
|
||||
void handle_player_actions() {
|
||||
// Can't attack while jumping
|
||||
if (player_arena_jumping) return;
|
||||
if (player_arena_jumping)
|
||||
return;
|
||||
|
||||
bool ctrl_down = (key_down(KEY_LCTRL) || key_down(KEY_RCTRL));
|
||||
|
||||
@@ -360,14 +367,18 @@ void handle_player_actions() {
|
||||
|
||||
// Non-sling weapon attacks (existing pattern)
|
||||
if (!bow_equipped && !bow_drawing && !sling_equipped && !sling_charging) {
|
||||
if (fishing_pole_equipped) return;
|
||||
if (fishing_pole_equipped)
|
||||
return;
|
||||
|
||||
int weapon_type = get_unicorn_melee_weapon_type();
|
||||
if (weapon_type == -1) return;
|
||||
if (weapon_type == -1)
|
||||
return;
|
||||
|
||||
int attack_cooldown = 1000;
|
||||
if (weapon_type == ADVENTURE_WEAPON_SPEAR) attack_cooldown = 800;
|
||||
if (weapon_type == ADVENTURE_WEAPON_AXE) attack_cooldown = 1600;
|
||||
if (weapon_type == ADVENTURE_WEAPON_SPEAR)
|
||||
attack_cooldown = 800;
|
||||
if (weapon_type == ADVENTURE_WEAPON_AXE)
|
||||
attack_cooldown = 1600;
|
||||
|
||||
if (ctrl_down && arena_attack_timer.elapsed > attack_cooldown) {
|
||||
arena_attack_timer.restart();
|
||||
@@ -380,8 +391,10 @@ void handle_player_actions() {
|
||||
}
|
||||
|
||||
int get_unicorn_melee_weapon_type() {
|
||||
if (spear_equipped) return ADVENTURE_WEAPON_SPEAR;
|
||||
if (axe_equipped) return ADVENTURE_WEAPON_AXE;
|
||||
if (spear_equipped)
|
||||
return ADVENTURE_WEAPON_SPEAR;
|
||||
if (axe_equipped)
|
||||
return ADVENTURE_WEAPON_AXE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -438,7 +451,8 @@ int find_unicorn_ranged_target(int player_x, int direction, int range) {
|
||||
|
||||
for (int dist = 1; dist <= range; dist++) {
|
||||
int check_x = player_x + (dist * direction);
|
||||
if (check_x < 0 || check_x >= UNICORN_ARENA_SIZE) break;
|
||||
if (check_x < 0 || check_x >= UNICORN_ARENA_SIZE)
|
||||
break;
|
||||
|
||||
if (bridge_supports_health[0] > 0 && check_x == BRIDGE_START) {
|
||||
return check_x;
|
||||
@@ -454,7 +468,8 @@ int find_unicorn_ranged_target(int player_x, int direction, int range) {
|
||||
|
||||
int unicorn_ranged_attack(int player_x, int direction, int range, int weapon_type, int damage) {
|
||||
int target_x = find_unicorn_ranged_target(player_x, direction, range);
|
||||
if (target_x == -1) return -1;
|
||||
if (target_x == -1)
|
||||
return -1;
|
||||
|
||||
if (target_x == unicorn.x) {
|
||||
apply_unicorn_damage(damage);
|
||||
@@ -482,7 +497,8 @@ int unicorn_ranged_attack(int player_x, int direction, int range, int weapon_typ
|
||||
}
|
||||
|
||||
void mark_unicorn_defeated(bool by_fall) {
|
||||
if (unicorn_defeated) return;
|
||||
if (unicorn_defeated)
|
||||
return;
|
||||
unicorn_defeated = true;
|
||||
unicorn_defeated_by_fall = by_fall;
|
||||
if (by_fall) {
|
||||
@@ -491,8 +507,10 @@ void mark_unicorn_defeated(bool by_fall) {
|
||||
}
|
||||
|
||||
void apply_unicorn_damage(int damage) {
|
||||
if (damage <= 0) return;
|
||||
if (unicorn.health <= 0) return;
|
||||
if (damage <= 0)
|
||||
return;
|
||||
if (unicorn.health <= 0)
|
||||
return;
|
||||
|
||||
unicorn.health -= damage;
|
||||
if (unicorn.health <= 0) {
|
||||
@@ -501,12 +519,15 @@ void apply_unicorn_damage(int damage) {
|
||||
}
|
||||
}
|
||||
|
||||
bool pet_find_unicorn_target(int originPos, int referencePos, int &out targetPos, string &out targetLabel, int &out targetKind) {
|
||||
bool pet_find_unicorn_target(int originPos, int referencePos, int& out targetPos, string& out targetLabel,
|
||||
int& out targetKind) {
|
||||
targetPos = -1;
|
||||
targetLabel = "";
|
||||
targetKind = -1;
|
||||
if (unicorn.health <= 0) return false;
|
||||
if (abs(unicorn.x - originPos) > PET_RANGE) return false;
|
||||
if (unicorn.health <= 0)
|
||||
return false;
|
||||
if (abs(unicorn.x - originPos) > PET_RANGE)
|
||||
return false;
|
||||
targetPos = unicorn.x;
|
||||
targetLabel = "unicorn";
|
||||
targetKind = 0;
|
||||
@@ -514,7 +535,8 @@ bool pet_find_unicorn_target(int originPos, int referencePos, int &out targetPos
|
||||
}
|
||||
|
||||
bool pet_damage_unicorn_target(int targetKind, int targetPos, int damage) {
|
||||
if (targetKind != 0) return false;
|
||||
if (targetKind != 0)
|
||||
return false;
|
||||
apply_unicorn_damage(damage);
|
||||
return true;
|
||||
}
|
||||
@@ -588,7 +610,8 @@ void update_unicorn_audio() {
|
||||
}
|
||||
|
||||
// Check if we need to switch sounds (different file or no active sound)
|
||||
bool need_new_sound = (unicorn.sound_handle == -1 || !p.sound_is_active(unicorn.sound_handle) || current_unicorn_sound != sound_file);
|
||||
bool need_new_sound =
|
||||
(unicorn.sound_handle == -1 || !p.sound_is_active(unicorn.sound_handle) || current_unicorn_sound != sound_file);
|
||||
|
||||
if (need_new_sound) {
|
||||
// Stop old sound if playing
|
||||
@@ -596,7 +619,8 @@ void update_unicorn_audio() {
|
||||
p.destroy_sound(unicorn.sound_handle);
|
||||
}
|
||||
// Start new positioned sound using shared helper
|
||||
unicorn.sound_handle = play_1d_with_volume_step(sound_file, player_arena_x, unicorn.x, true, UNICORN_SOUND_VOLUME_STEP);
|
||||
unicorn.sound_handle =
|
||||
play_1d_with_volume_step(sound_file, player_arena_x, unicorn.x, true, UNICORN_SOUND_VOLUME_STEP);
|
||||
current_unicorn_sound = sound_file;
|
||||
} else {
|
||||
// Update position of existing sound
|
||||
@@ -630,10 +654,13 @@ void play_unicorn_death_sequence() {
|
||||
// Pitch ranges from 100 (start) to 50 (end) like normal falling
|
||||
float height_remaining = float(total_fall - feet_fallen);
|
||||
float pitch_percent = 50.0 + (50.0 * (height_remaining / float(total_fall)));
|
||||
if (pitch_percent < 50.0) pitch_percent = 50.0;
|
||||
if (pitch_percent > 100.0) pitch_percent = 100.0;
|
||||
if (pitch_percent < 50.0)
|
||||
pitch_percent = 50.0;
|
||||
if (pitch_percent > 100.0)
|
||||
pitch_percent = 100.0;
|
||||
|
||||
fall_handle = p.play_extended_1d("sounds/actions/falling.ogg", player_arena_x, unicorn.x, 0, 0, true, 0, 0.0, 0.0, pitch_percent);
|
||||
fall_handle = p.play_extended_1d("sounds/actions/falling.ogg", player_arena_x, unicorn.x, 0, 0, true, 0,
|
||||
0.0, 0.0, pitch_percent);
|
||||
if (fall_handle != -1) {
|
||||
p.update_sound_positioning_values(fall_handle, -1.0, UNICORN_SOUND_VOLUME_STEP, true);
|
||||
}
|
||||
@@ -645,7 +672,8 @@ void play_unicorn_death_sequence() {
|
||||
if (fall_handle != -1) {
|
||||
p.destroy_sound(fall_handle);
|
||||
}
|
||||
play_1d_with_volume_step("sounds/bosses/unicorn/unicorn_falls.ogg", player_arena_x, unicorn.x, false, UNICORN_SOUND_VOLUME_STEP);
|
||||
play_1d_with_volume_step("sounds/bosses/unicorn/unicorn_falls.ogg", player_arena_x, unicorn.x, false,
|
||||
UNICORN_SOUND_VOLUME_STEP);
|
||||
wait(1500); // Let the impact sound play before cleanup
|
||||
}
|
||||
|
||||
|
||||
+53
-47
@@ -30,34 +30,36 @@ void speak_ammo_blocked(string message) {
|
||||
speak_with_history(message, true);
|
||||
}
|
||||
|
||||
int find_ranged_enemy(int player_x, int range, int direction, bool allow_flying, bool &out hit_bandit, bool &out hit_boar, bool &out hit_flying_creature) {
|
||||
int find_ranged_enemy(int player_x, int range, int direction, bool allow_flying, bool& out hit_bandit,
|
||||
bool& out hit_boar, bool& out hit_flying_creature) {
|
||||
hit_bandit = false;
|
||||
hit_boar = false;
|
||||
hit_flying_creature = false;
|
||||
|
||||
for (int dist = 1; dist <= range; dist++) {
|
||||
int check_x = player_x + (dist * direction);
|
||||
if (check_x < 0 || check_x >= MAP_SIZE) break;
|
||||
if (check_x < 0 || check_x >= MAP_SIZE)
|
||||
break;
|
||||
|
||||
Bandit@ bandit = get_bandit_at(check_x);
|
||||
Bandit @bandit = get_bandit_at(check_x);
|
||||
if (bandit != null) {
|
||||
hit_bandit = true;
|
||||
return check_x;
|
||||
}
|
||||
|
||||
GroundGame@ boar = get_boar_at(check_x);
|
||||
GroundGame @boar = get_boar_at(check_x);
|
||||
if (boar != null) {
|
||||
hit_boar = true;
|
||||
return check_x;
|
||||
}
|
||||
|
||||
Undead@ undead = get_zombie_at(check_x);
|
||||
Undead @undead = get_zombie_at(check_x);
|
||||
if (undead != null) {
|
||||
return check_x;
|
||||
}
|
||||
|
||||
if (allow_flying) {
|
||||
FlyingCreature@ creature = get_flying_creature_at(check_x);
|
||||
FlyingCreature @creature = get_flying_creature_at(check_x);
|
||||
if (creature != null && creature.state == "flying") {
|
||||
hit_flying_creature = true;
|
||||
return check_x;
|
||||
@@ -152,7 +154,7 @@ void perform_sling_attack(int current_x) {
|
||||
}
|
||||
|
||||
void hit_tree_with_spear(int target_x) {
|
||||
Tree@ target = get_tree_at(target_x);
|
||||
Tree @target = get_tree_at(target_x);
|
||||
if (@target != null && !target.is_chopped) {
|
||||
p.play_stationary("sounds/weapons/spear_hit.ogg", false);
|
||||
}
|
||||
@@ -184,13 +186,17 @@ void update_sling_charge() {
|
||||
|
||||
int get_bow_draw_damage(int elapsed_ms) {
|
||||
int clamped = elapsed_ms;
|
||||
if (clamped < 0) clamped = 0;
|
||||
if (clamped > BOW_DRAW_TIME_MS) clamped = BOW_DRAW_TIME_MS;
|
||||
if (clamped < 0)
|
||||
clamped = 0;
|
||||
if (clamped > BOW_DRAW_TIME_MS)
|
||||
clamped = BOW_DRAW_TIME_MS;
|
||||
|
||||
float ratio = float(clamped) / float(BOW_DRAW_TIME_MS);
|
||||
int damage = int(ratio * BOW_DAMAGE_MAX);
|
||||
if (damage < BOW_DAMAGE_MIN) damage = BOW_DAMAGE_MIN;
|
||||
if (damage > BOW_DAMAGE_MAX) damage = BOW_DAMAGE_MAX;
|
||||
if (damage < BOW_DAMAGE_MIN)
|
||||
damage = BOW_DAMAGE_MIN;
|
||||
if (damage > BOW_DAMAGE_MAX)
|
||||
damage = BOW_DAMAGE_MAX;
|
||||
return damage;
|
||||
}
|
||||
|
||||
@@ -213,24 +219,23 @@ void start_bow_shot_audio(int start_x, int end_x, int hit_x, int hit_type, int d
|
||||
bow_shot_duration_ms = duration_ms;
|
||||
bow_shot_drop_pending = false;
|
||||
bow_shot_drop_pos = -1;
|
||||
if (bow_shot_duration_ms < 1) bow_shot_duration_ms = 1;
|
||||
if (bow_shot_duration_ms < 1)
|
||||
bow_shot_duration_ms = 1;
|
||||
|
||||
bow_shot_sound_handle = play_1d_with_volume_step(
|
||||
"sounds/weapons/arrow_flies.ogg",
|
||||
x,
|
||||
bow_shot_start_x,
|
||||
false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP
|
||||
);
|
||||
bow_shot_sound_handle = play_1d_with_volume_step("sounds/weapons/arrow_flies.ogg", x, bow_shot_start_x, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
void update_bow_shot() {
|
||||
if (!bow_shot_active) return;
|
||||
if (bow_shot_duration_ms < 1) bow_shot_duration_ms = 1;
|
||||
if (!bow_shot_active)
|
||||
return;
|
||||
if (bow_shot_duration_ms < 1)
|
||||
bow_shot_duration_ms = 1;
|
||||
|
||||
int elapsed = bow_shot_timer.elapsed;
|
||||
float progress = float(elapsed) / float(bow_shot_duration_ms);
|
||||
if (progress > 1.0f) progress = 1.0f;
|
||||
if (progress > 1.0f)
|
||||
progress = 1.0f;
|
||||
|
||||
int travel = int(float(bow_shot_end_x - bow_shot_start_x) * progress);
|
||||
int current_pos = bow_shot_start_x + travel;
|
||||
@@ -245,13 +250,7 @@ void update_bow_shot() {
|
||||
int drop_pos = bow_shot_drop_pos;
|
||||
stop_bow_shot_audio();
|
||||
if (hit_x >= 0) {
|
||||
play_1d_with_volume_step(
|
||||
"sounds/weapons/arrow_hit.ogg",
|
||||
x,
|
||||
hit_x,
|
||||
false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP
|
||||
);
|
||||
play_1d_with_volume_step("sounds/weapons/arrow_hit.ogg", x, hit_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
if (hit_type == BOW_HIT_BANDIT) {
|
||||
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", x, hit_x, BANDIT_SOUND_VOLUME_STEP);
|
||||
} else if (hit_type == BOW_HIT_BOAR) {
|
||||
@@ -283,14 +282,16 @@ void release_bow_attack(int player_x) {
|
||||
bool hit_bandit = false;
|
||||
bool hit_flying_creature = false;
|
||||
bool hit_boar = false;
|
||||
int target_x = find_ranged_enemy(player_x, BOW_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
|
||||
int target_x =
|
||||
find_ranged_enemy(player_x, BOW_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
|
||||
bool hit_tree = false;
|
||||
|
||||
if (target_x == -1) {
|
||||
for (int dist = 1; dist <= BOW_RANGE; dist++) {
|
||||
int check_x = player_x + (dist * search_direction);
|
||||
if (check_x < 0 || check_x >= MAP_SIZE) break;
|
||||
Tree@ tree = get_tree_at(check_x);
|
||||
if (check_x < 0 || check_x >= MAP_SIZE)
|
||||
break;
|
||||
Tree @tree = get_tree_at(check_x);
|
||||
if (tree != null && !tree.is_chopped) {
|
||||
target_x = check_x;
|
||||
hit_tree = true;
|
||||
@@ -318,16 +319,16 @@ void release_bow_attack(int player_x) {
|
||||
hit_type = BOW_HIT_NONE;
|
||||
}
|
||||
|
||||
int end_x = (target_x != -1)
|
||||
? target_x
|
||||
: (player_x + (search_direction * (BOW_RANGE + BOW_MISS_EXTRA_TILES)));
|
||||
int end_x = (target_x != -1) ? target_x : (player_x + (search_direction * (BOW_RANGE + BOW_MISS_EXTRA_TILES)));
|
||||
|
||||
int duration_ms = ARROW_FLIES_DURATION_MS;
|
||||
if (target_x != -1) {
|
||||
int distance = abs(target_x - player_x);
|
||||
if (distance < 1) distance = 1;
|
||||
if (distance < 1)
|
||||
distance = 1;
|
||||
duration_ms = int(float(ARROW_FLIES_DURATION_MS) * (float(distance) / float(BOW_RANGE)));
|
||||
if (duration_ms < 1) duration_ms = 1;
|
||||
if (duration_ms < 1)
|
||||
duration_ms = 1;
|
||||
}
|
||||
|
||||
int hit_x = (target_x != -1) ? target_x : -1;
|
||||
@@ -349,7 +350,6 @@ void release_sling_attack(int player_x) {
|
||||
|
||||
// Only hit if released during in-range window (stage 1)
|
||||
if (stage != 1) {
|
||||
speak_with_history("Stone missed.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -359,17 +359,20 @@ void release_sling_attack(int player_x) {
|
||||
bool hit_bandit = false;
|
||||
bool hit_flying_creature = false;
|
||||
bool hit_boar = false;
|
||||
target_x = find_ranged_enemy(player_x, SLING_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
|
||||
target_x =
|
||||
find_ranged_enemy(player_x, SLING_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
|
||||
|
||||
// If no enemy found, check for trees (but don't damage them)
|
||||
if (target_x == -1) {
|
||||
for (int dist = 1; dist <= SLING_RANGE; dist++) {
|
||||
int check_x = player_x + (dist * search_direction);
|
||||
if (check_x < 0 || check_x >= MAP_SIZE) break;
|
||||
Tree@ tree = get_tree_at(check_x);
|
||||
if (check_x < 0 || check_x >= MAP_SIZE)
|
||||
break;
|
||||
Tree @tree = get_tree_at(check_x);
|
||||
if (tree != null && !tree.is_chopped) {
|
||||
// Stone hits tree but doesn't damage it
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, check_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, check_x, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -377,7 +380,6 @@ void release_sling_attack(int player_x) {
|
||||
|
||||
// No target found
|
||||
if (target_x == -1) {
|
||||
speak_with_history("Stone missed.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -387,19 +389,23 @@ void release_sling_attack(int player_x) {
|
||||
// Damage the correct enemy type
|
||||
if (hit_bandit) {
|
||||
damage_bandit_at(target_x, damage);
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", player_x, target_x, BANDIT_SOUND_VOLUME_STEP);
|
||||
} else if (hit_boar) {
|
||||
damage_boar_at(target_x, damage);
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", player_x, target_x, BOAR_SOUND_VOLUME_STEP);
|
||||
} else if (hit_flying_creature) {
|
||||
damage_flying_creature_at(target_x, damage);
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
// Falling sound handled by damage_flying_creature_at
|
||||
} else {
|
||||
damage_zombie_at(target_x, damage);
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", player_x, target_x, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,6 +277,7 @@ const int PET_KNOCKOUT_COOLDOWN_HOURS = 4;
|
||||
const float PET_CHARGE_SPEED_MULTIPLIER = 1.5;
|
||||
const int PET_FOLLOW_COMFORT_DISTANCE = 2;
|
||||
const int PET_FOLLOW_MAX_DISTANCE = 5;
|
||||
const int PET_LEAVE_DESPAWN_DISTANCE = 20;
|
||||
|
||||
// Goose settings
|
||||
const int GOOSE_HEALTH = 1;
|
||||
|
||||
@@ -10,19 +10,23 @@ void run_barricade_menu() {
|
||||
int[] action_types; // 0 = sticks, 1 = vines, 2 = log, 3 = stones
|
||||
|
||||
if (get_personal_count(ITEM_STICKS) >= BARRICADE_STICK_COST) {
|
||||
options.insert_last("Reinforce with sticks (" + BARRICADE_STICK_COST + " sticks, +" + BARRICADE_STICK_HEALTH + " health)");
|
||||
options.insert_last("Reinforce with sticks (" + BARRICADE_STICK_COST + " sticks, +" + BARRICADE_STICK_HEALTH +
|
||||
" health)");
|
||||
action_types.insert_last(0);
|
||||
}
|
||||
if (get_personal_count(ITEM_VINES) >= BARRICADE_VINE_COST) {
|
||||
options.insert_last("Reinforce with vines (" + BARRICADE_VINE_COST + " vines, +" + BARRICADE_VINE_HEALTH + " health)");
|
||||
options.insert_last("Reinforce with vines (" + BARRICADE_VINE_COST + " vines, +" + BARRICADE_VINE_HEALTH +
|
||||
" health)");
|
||||
action_types.insert_last(1);
|
||||
}
|
||||
if (get_personal_count(ITEM_LOGS) >= BARRICADE_LOG_COST) {
|
||||
options.insert_last("Reinforce with log (" + BARRICADE_LOG_COST + " log, +" + BARRICADE_LOG_HEALTH + " health)");
|
||||
options.insert_last("Reinforce with log (" + BARRICADE_LOG_COST + " log, +" + BARRICADE_LOG_HEALTH +
|
||||
" health)");
|
||||
action_types.insert_last(2);
|
||||
}
|
||||
if (get_personal_count(ITEM_STONES) >= BARRICADE_STONE_COST) {
|
||||
options.insert_last("Reinforce with stones (" + BARRICADE_STONE_COST + " stones, +" + BARRICADE_STONE_HEALTH + " health)");
|
||||
options.insert_last("Reinforce with stones (" + BARRICADE_STONE_COST + " stones, +" + BARRICADE_STONE_HEALTH +
|
||||
" health)");
|
||||
action_types.insert_last(3);
|
||||
}
|
||||
|
||||
@@ -32,7 +36,7 @@ void run_barricade_menu() {
|
||||
}
|
||||
speak_with_history("Barricade. " + options[selection], true);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -45,34 +49,44 @@ void run_barricade_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= options.length()) selection = 0;
|
||||
if (selection >= options.length())
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = options.length() - 1;
|
||||
if (selection < 0)
|
||||
selection = options.length() - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
play_menu_select_sound();
|
||||
int action = action_types[selection];
|
||||
if (action == 0) reinforce_barricade_with_sticks();
|
||||
else if (action == 1) reinforce_barricade_with_vines();
|
||||
else if (action == 2) reinforce_barricade_with_log();
|
||||
else if (action == 3) reinforce_barricade_with_stones();
|
||||
if (action == 0)
|
||||
reinforce_barricade_with_sticks();
|
||||
else if (action == 1)
|
||||
reinforce_barricade_with_vines();
|
||||
else if (action == 2)
|
||||
reinforce_barricade_with_log();
|
||||
else if (action == 3)
|
||||
reinforce_barricade_with_stones();
|
||||
break;
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_TAB)) {
|
||||
play_menu_select_sound();
|
||||
int action = action_types[selection];
|
||||
if (action == 0) reinforce_barricade_max_with_sticks();
|
||||
else if (action == 1) reinforce_barricade_max_with_vines();
|
||||
else if (action == 2) reinforce_barricade_max_with_log();
|
||||
else if (action == 3) reinforce_barricade_max_with_stones();
|
||||
if (action == 0)
|
||||
reinforce_barricade_max_with_sticks();
|
||||
else if (action == 1)
|
||||
reinforce_barricade_max_with_vines();
|
||||
else if (action == 2)
|
||||
reinforce_barricade_max_with_log();
|
||||
else if (action == 3)
|
||||
reinforce_barricade_max_with_stones();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -91,7 +105,9 @@ void reinforce_barricade_with_sticks() {
|
||||
simulate_crafting(BARRICADE_STICK_COST);
|
||||
add_personal_count(ITEM_STICKS, -BARRICADE_STICK_COST);
|
||||
int gained = add_barricade_health(BARRICADE_STICK_HEALTH);
|
||||
speak_with_history("Reinforced barricade with sticks. +" + gained + " health. Now " + barricade_health + " of " + BARRICADE_MAX_HEALTH + ".", true);
|
||||
speak_with_history("Reinforced barricade with sticks. +" + gained + " health. Now " + barricade_health + " of " +
|
||||
BARRICADE_MAX_HEALTH + ".",
|
||||
true);
|
||||
}
|
||||
|
||||
void reinforce_barricade_with_vines() {
|
||||
@@ -107,7 +123,9 @@ void reinforce_barricade_with_vines() {
|
||||
simulate_crafting(BARRICADE_VINE_COST);
|
||||
add_personal_count(ITEM_VINES, -BARRICADE_VINE_COST);
|
||||
int gained = add_barricade_health(BARRICADE_VINE_HEALTH);
|
||||
speak_with_history("Reinforced barricade with vines. +" + gained + " health. Now " + barricade_health + " of " + BARRICADE_MAX_HEALTH + ".", true);
|
||||
speak_with_history("Reinforced barricade with vines. +" + gained + " health. Now " + barricade_health + " of " +
|
||||
BARRICADE_MAX_HEALTH + ".",
|
||||
true);
|
||||
}
|
||||
|
||||
void reinforce_barricade_with_log() {
|
||||
@@ -123,7 +141,9 @@ void reinforce_barricade_with_log() {
|
||||
simulate_crafting(BARRICADE_LOG_COST);
|
||||
add_personal_count(ITEM_LOGS, -BARRICADE_LOG_COST);
|
||||
int gained = add_barricade_health(BARRICADE_LOG_HEALTH);
|
||||
speak_with_history("Reinforced barricade with log. +" + gained + " health. Now " + barricade_health + " of " + BARRICADE_MAX_HEALTH + ".", true);
|
||||
speak_with_history("Reinforced barricade with log. +" + gained + " health. Now " + barricade_health + " of " +
|
||||
BARRICADE_MAX_HEALTH + ".",
|
||||
true);
|
||||
}
|
||||
|
||||
void reinforce_barricade_with_stones() {
|
||||
@@ -139,7 +159,9 @@ void reinforce_barricade_with_stones() {
|
||||
simulate_crafting(BARRICADE_STONE_COST);
|
||||
add_personal_count(ITEM_STONES, -BARRICADE_STONE_COST);
|
||||
int gained = add_barricade_health(BARRICADE_STONE_HEALTH);
|
||||
speak_with_history("Reinforced barricade with stones. +" + gained + " health. Now " + barricade_health + " of " + BARRICADE_MAX_HEALTH + ".", true);
|
||||
speak_with_history("Reinforced barricade with stones. +" + gained + " health. Now " + barricade_health + " of " +
|
||||
BARRICADE_MAX_HEALTH + ".",
|
||||
true);
|
||||
}
|
||||
|
||||
void reinforce_barricade_max_with_sticks() {
|
||||
@@ -164,9 +186,11 @@ void reinforce_barricade_max_with_sticks() {
|
||||
simulate_crafting(craft_time);
|
||||
add_personal_count(ITEM_STICKS, -total_cost);
|
||||
barricade_health += (to_do * BARRICADE_STICK_HEALTH);
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH) barricade_health = BARRICADE_MAX_HEALTH;
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH)
|
||||
barricade_health = BARRICADE_MAX_HEALTH;
|
||||
|
||||
speak_with_history("Reinforced barricade " + to_do + " times with sticks. Health now " + barricade_health + ".", true);
|
||||
speak_with_history("Reinforced barricade " + to_do + " times with sticks. Health now " + barricade_health + ".",
|
||||
true);
|
||||
}
|
||||
|
||||
void reinforce_barricade_max_with_vines() {
|
||||
@@ -191,9 +215,11 @@ void reinforce_barricade_max_with_vines() {
|
||||
simulate_crafting(craft_time);
|
||||
add_personal_count(ITEM_VINES, -total_cost);
|
||||
barricade_health += (to_do * BARRICADE_VINE_HEALTH);
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH) barricade_health = BARRICADE_MAX_HEALTH;
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH)
|
||||
barricade_health = BARRICADE_MAX_HEALTH;
|
||||
|
||||
speak_with_history("Reinforced barricade " + to_do + " times with vines. Health now " + barricade_health + ".", true);
|
||||
speak_with_history("Reinforced barricade " + to_do + " times with vines. Health now " + barricade_health + ".",
|
||||
true);
|
||||
}
|
||||
|
||||
void reinforce_barricade_max_with_log() {
|
||||
@@ -218,7 +244,8 @@ void reinforce_barricade_max_with_log() {
|
||||
simulate_crafting(craft_time);
|
||||
add_personal_count(ITEM_LOGS, -total_cost);
|
||||
barricade_health += (to_do * BARRICADE_LOG_HEALTH);
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH) barricade_health = BARRICADE_MAX_HEALTH;
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH)
|
||||
barricade_health = BARRICADE_MAX_HEALTH;
|
||||
|
||||
speak_with_history("Reinforced barricade " + to_do + " times with log. Health now " + barricade_health + ".", true);
|
||||
}
|
||||
@@ -245,7 +272,9 @@ void reinforce_barricade_max_with_stones() {
|
||||
simulate_crafting(craft_time);
|
||||
add_personal_count(ITEM_STONES, -total_cost);
|
||||
barricade_health += (to_do * BARRICADE_STONE_HEALTH);
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH) barricade_health = BARRICADE_MAX_HEALTH;
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH)
|
||||
barricade_health = BARRICADE_MAX_HEALTH;
|
||||
|
||||
speak_with_history("Reinforced barricade " + to_do + " times with stones. Health now " + barricade_health + ".", true);
|
||||
speak_with_history("Reinforced barricade " + to_do + " times with stones. Health now " + barricade_health + ".",
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -15,13 +15,20 @@ bool has_building_options() {
|
||||
}
|
||||
}
|
||||
|
||||
if (x > BASE_END || !base_has_firepit) return true;
|
||||
if (x > BASE_END || !base_has_fire) return true;
|
||||
if (get_herb_garden_at_base() == null) return true;
|
||||
if (storage_level < STORAGE_LEVEL_UPGRADE_2) return true;
|
||||
if (world_pastures.length() == 0 && storage_level >= STORAGE_LEVEL_UPGRADE_1) return true;
|
||||
if (world_stables.length() == 0 && storage_level >= STORAGE_LEVEL_UPGRADE_1) return true;
|
||||
if (world_altars.length() == 0) return true;
|
||||
if (x > BASE_END || !base_has_firepit)
|
||||
return true;
|
||||
if (x > BASE_END || !base_has_fire)
|
||||
return true;
|
||||
if (get_herb_garden_at_base() == null)
|
||||
return true;
|
||||
if (storage_level < STORAGE_LEVEL_UPGRADE_2)
|
||||
return true;
|
||||
if (world_pastures.length() == 0 && storage_level >= STORAGE_LEVEL_UPGRADE_1)
|
||||
return true;
|
||||
if (world_stables.length() == 0 && storage_level >= STORAGE_LEVEL_UPGRADE_1)
|
||||
return true;
|
||||
if (world_altars.length() == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -95,7 +102,7 @@ void run_buildings_menu() {
|
||||
}
|
||||
speak_with_history("Buildings. " + options[selection], true);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -108,27 +115,36 @@ void run_buildings_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= options.length()) selection = 0;
|
||||
if (selection >= options.length())
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = options.length() - 1;
|
||||
if (selection < 0)
|
||||
selection = options.length() - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
play_menu_select_sound();
|
||||
int building = building_types[selection];
|
||||
if (building == 0) craft_firepit();
|
||||
else if (building == 1) craft_campfire();
|
||||
else if (building == 2) craft_herb_garden();
|
||||
else if (building == 3) craft_storage();
|
||||
else if (building == 4) craft_pasture();
|
||||
else if (building == 5) craft_stable();
|
||||
else if (building == 6) craft_altar();
|
||||
if (building == 0)
|
||||
craft_firepit();
|
||||
else if (building == 1)
|
||||
craft_campfire();
|
||||
else if (building == 2)
|
||||
craft_herb_garden();
|
||||
else if (building == 3)
|
||||
craft_storage();
|
||||
else if (building == 4)
|
||||
craft_pasture();
|
||||
else if (building == 5)
|
||||
craft_stable();
|
||||
else if (building == 6)
|
||||
craft_altar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -152,7 +168,8 @@ void craft_firepit() {
|
||||
}
|
||||
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STONES) < 9) missing += "9 stones ";
|
||||
if (get_personal_count(ITEM_STONES) < 9)
|
||||
missing += "9 stones ";
|
||||
|
||||
if (missing == "") {
|
||||
simulate_crafting(9);
|
||||
@@ -166,7 +183,7 @@ void craft_firepit() {
|
||||
|
||||
void craft_campfire() {
|
||||
// Check if there's a firepit within 2 tiles
|
||||
WorldFirepit@ firepit = get_firepit_near(x, 2);
|
||||
WorldFirepit @firepit = get_firepit_near(x, 2);
|
||||
if (firepit == null) {
|
||||
speak_with_history("You need a firepit within 2 tiles to build a fire.", true);
|
||||
return;
|
||||
@@ -183,8 +200,10 @@ void craft_campfire() {
|
||||
}
|
||||
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_LOGS) < 1) missing += "1 log ";
|
||||
if (get_personal_count(ITEM_STICKS) < 2) missing += "2 sticks ";
|
||||
if (get_personal_count(ITEM_LOGS) < 1)
|
||||
missing += "1 log ";
|
||||
if (get_personal_count(ITEM_STICKS) < 2)
|
||||
missing += "2 sticks ";
|
||||
|
||||
if (missing == "") {
|
||||
simulate_crafting(3);
|
||||
@@ -212,9 +231,12 @@ void craft_herb_garden() {
|
||||
}
|
||||
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STONES) < 9) missing += "9 stones ";
|
||||
if (get_personal_count(ITEM_VINES) < 3) missing += "3 vines ";
|
||||
if (get_personal_count(ITEM_LOGS) < 2) missing += "2 logs ";
|
||||
if (get_personal_count(ITEM_STONES) < 9)
|
||||
missing += "9 stones ";
|
||||
if (get_personal_count(ITEM_VINES) < 3)
|
||||
missing += "3 vines ";
|
||||
if (get_personal_count(ITEM_LOGS) < 2)
|
||||
missing += "2 logs ";
|
||||
|
||||
if (missing == "") {
|
||||
simulate_crafting(14);
|
||||
@@ -252,9 +274,12 @@ void craft_storage() {
|
||||
newCapacity = BASE_STORAGE_UPGRADE_2_MAX;
|
||||
craftTime = 46;
|
||||
}
|
||||
if (get_personal_count(ITEM_LOGS) < logCost) missing += logCost + " logs ";
|
||||
if (get_personal_count(ITEM_STONES) < stoneCost) missing += stoneCost + " stones ";
|
||||
if (get_personal_count(ITEM_VINES) < vineCost) missing += vineCost + " vines ";
|
||||
if (get_personal_count(ITEM_LOGS) < logCost)
|
||||
missing += logCost + " logs ";
|
||||
if (get_personal_count(ITEM_STONES) < stoneCost)
|
||||
missing += stoneCost + " stones ";
|
||||
if (get_personal_count(ITEM_VINES) < vineCost)
|
||||
missing += vineCost + " vines ";
|
||||
|
||||
if (missing == "") {
|
||||
simulate_crafting(craftTime);
|
||||
@@ -285,8 +310,10 @@ void craft_pasture() {
|
||||
return;
|
||||
}
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_LOGS) < PASTURE_LOG_COST) missing += PASTURE_LOG_COST + " logs ";
|
||||
if (get_personal_count(ITEM_ROPES) < PASTURE_ROPE_COST) missing += PASTURE_ROPE_COST + " ropes ";
|
||||
if (get_personal_count(ITEM_LOGS) < PASTURE_LOG_COST)
|
||||
missing += PASTURE_LOG_COST + " logs ";
|
||||
if (get_personal_count(ITEM_ROPES) < PASTURE_ROPE_COST)
|
||||
missing += PASTURE_ROPE_COST + " ropes ";
|
||||
|
||||
if (missing == "") {
|
||||
simulate_crafting(28);
|
||||
@@ -313,9 +340,12 @@ void craft_stable() {
|
||||
return;
|
||||
}
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_LOGS) < STABLE_LOG_COST) missing += STABLE_LOG_COST + " logs ";
|
||||
if (get_personal_count(ITEM_STONES) < STABLE_STONE_COST) missing += STABLE_STONE_COST + " stones ";
|
||||
if (get_personal_count(ITEM_VINES) < STABLE_VINE_COST) missing += STABLE_VINE_COST + " vines ";
|
||||
if (get_personal_count(ITEM_LOGS) < STABLE_LOG_COST)
|
||||
missing += STABLE_LOG_COST + " logs ";
|
||||
if (get_personal_count(ITEM_STONES) < STABLE_STONE_COST)
|
||||
missing += STABLE_STONE_COST + " stones ";
|
||||
if (get_personal_count(ITEM_VINES) < STABLE_VINE_COST)
|
||||
missing += STABLE_VINE_COST + " vines ";
|
||||
|
||||
if (missing == "") {
|
||||
simulate_crafting(35);
|
||||
@@ -339,8 +369,10 @@ void craft_altar() {
|
||||
return;
|
||||
}
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STONES) < ALTAR_STONE_COST) missing += ALTAR_STONE_COST + " stones ";
|
||||
if (get_personal_count(ITEM_STICKS) < ALTAR_STICK_COST) missing += ALTAR_STICK_COST + " sticks ";
|
||||
if (get_personal_count(ITEM_STONES) < ALTAR_STONE_COST)
|
||||
missing += ALTAR_STONE_COST + " stones ";
|
||||
if (get_personal_count(ITEM_STICKS) < ALTAR_STICK_COST)
|
||||
missing += ALTAR_STICK_COST + " sticks ";
|
||||
|
||||
if (missing == "") {
|
||||
simulate_crafting(12);
|
||||
|
||||
@@ -44,18 +44,16 @@ void consume_pouches(int amount) {
|
||||
|
||||
void run_clothing_menu() {
|
||||
int selection = 0;
|
||||
string[] options = {
|
||||
"Skin Hat (1 Skin, 1 Vine)",
|
||||
string[] options = {"Skin Hat (1 Skin, 1 Vine)",
|
||||
"Skin Gloves (1 Skin, 1 Vine)",
|
||||
"Skin Pants (6 Skins, 3 Vines)",
|
||||
"Skin Tunic (4 Skins, 2 Vines)",
|
||||
"Moccasins (2 Skins, 1 Vine)",
|
||||
"Skin Pouch (2 Skins, 1 Vine)",
|
||||
"Backpack (11 Skins, 5 Vines, 4 Skin Pouches)"
|
||||
};
|
||||
"Backpack (11 Skins, 5 Vines, 4 Skin Pouches)"};
|
||||
speak_with_history("Clothing. " + options[selection], true);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -68,38 +66,54 @@ void run_clothing_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= options.length()) selection = 0;
|
||||
if (selection >= options.length())
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = options.length() - 1;
|
||||
if (selection < 0)
|
||||
selection = options.length() - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
play_menu_select_sound();
|
||||
if (selection == 0) craft_skin_hat();
|
||||
else if (selection == 1) craft_skin_gloves();
|
||||
else if (selection == 2) craft_skin_pants();
|
||||
else if (selection == 3) craft_skin_tunic();
|
||||
else if (selection == 4) craft_moccasins();
|
||||
else if (selection == 5) craft_skin_pouch();
|
||||
else if (selection == 6) craft_backpack();
|
||||
if (selection == 0)
|
||||
craft_skin_hat();
|
||||
else if (selection == 1)
|
||||
craft_skin_gloves();
|
||||
else if (selection == 2)
|
||||
craft_skin_pants();
|
||||
else if (selection == 3)
|
||||
craft_skin_tunic();
|
||||
else if (selection == 4)
|
||||
craft_moccasins();
|
||||
else if (selection == 5)
|
||||
craft_skin_pouch();
|
||||
else if (selection == 6)
|
||||
craft_backpack();
|
||||
break;
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_TAB)) {
|
||||
play_menu_select_sound();
|
||||
if (selection == 0) craft_skin_hat_max();
|
||||
else if (selection == 1) craft_skin_gloves_max();
|
||||
else if (selection == 2) craft_skin_pants_max();
|
||||
else if (selection == 3) craft_skin_tunic_max();
|
||||
else if (selection == 4) craft_moccasins_max();
|
||||
else if (selection == 5) craft_skin_pouch_max();
|
||||
else if (selection == 6) craft_backpack_max();
|
||||
if (selection == 0)
|
||||
craft_skin_hat_max();
|
||||
else if (selection == 1)
|
||||
craft_skin_gloves_max();
|
||||
else if (selection == 2)
|
||||
craft_skin_pants_max();
|
||||
else if (selection == 3)
|
||||
craft_skin_tunic_max();
|
||||
else if (selection == 4)
|
||||
craft_moccasins_max();
|
||||
else if (selection == 5)
|
||||
craft_skin_pouch_max();
|
||||
else if (selection == 6)
|
||||
craft_backpack_max();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -107,8 +121,10 @@ void run_clothing_menu() {
|
||||
|
||||
void craft_skin_hat() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_SKINS) < 1)
|
||||
missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SKIN_HATS) >= get_personal_stack_limit()) {
|
||||
@@ -134,15 +150,19 @@ void craft_skin_hat_max() {
|
||||
int max_by_skins = get_personal_count(ITEM_SKINS);
|
||||
int max_by_vines = get_personal_count(ITEM_VINES);
|
||||
int max_craft = max_by_skins;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_HATS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_SKINS) < 1)
|
||||
missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -158,8 +178,10 @@ void craft_skin_hat_max() {
|
||||
|
||||
void craft_skin_gloves() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_SKINS) < 1)
|
||||
missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SKIN_GLOVES) >= get_personal_stack_limit()) {
|
||||
@@ -185,15 +207,19 @@ void craft_skin_gloves_max() {
|
||||
int max_by_skins = get_personal_count(ITEM_SKINS);
|
||||
int max_by_vines = get_personal_count(ITEM_VINES);
|
||||
int max_craft = max_by_skins;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_GLOVES);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_SKINS) < 1)
|
||||
missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -209,8 +235,10 @@ void craft_skin_gloves_max() {
|
||||
|
||||
void craft_skin_pants() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 3) missing += "3 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 6)
|
||||
missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 3)
|
||||
missing += "3 vines ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SKIN_PANTS) >= get_personal_stack_limit()) {
|
||||
@@ -236,15 +264,19 @@ void craft_skin_pants_max() {
|
||||
int max_by_skins = get_personal_count(ITEM_SKINS) / 6;
|
||||
int max_by_vines = get_personal_count(ITEM_VINES) / 3;
|
||||
int max_craft = max_by_skins;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_PANTS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 3) missing += "3 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 6)
|
||||
missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 3)
|
||||
missing += "3 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -259,8 +291,10 @@ void craft_skin_pants_max() {
|
||||
|
||||
void craft_skin_tunic() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 4) missing += "4 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 4)
|
||||
missing += "4 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SKIN_TUNICS) >= get_personal_stack_limit()) {
|
||||
@@ -286,15 +320,19 @@ void craft_skin_tunic_max() {
|
||||
int max_by_skins = get_personal_count(ITEM_SKINS) / 4;
|
||||
int max_by_vines = get_personal_count(ITEM_VINES) / 2;
|
||||
int max_craft = max_by_skins;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_TUNICS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 4) missing += "4 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 4)
|
||||
missing += "4 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -309,8 +347,10 @@ void craft_skin_tunic_max() {
|
||||
|
||||
void craft_moccasins() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_SKINS) < 2)
|
||||
missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_MOCCASINS) >= get_personal_stack_limit()) {
|
||||
@@ -336,15 +376,19 @@ void craft_moccasins_max() {
|
||||
int max_by_skins = get_personal_count(ITEM_SKINS) / 2;
|
||||
int max_by_vines = get_personal_count(ITEM_VINES);
|
||||
int max_craft = max_by_skins;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_MOCCASINS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_SKINS) < 2)
|
||||
missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -360,8 +404,10 @@ void craft_moccasins_max() {
|
||||
|
||||
void craft_skin_pouch() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_SKINS) < 2)
|
||||
missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SKIN_POUCHES) >= get_personal_stack_limit()) {
|
||||
@@ -387,15 +433,19 @@ void craft_skin_pouch_max() {
|
||||
int max_by_skins = get_personal_count(ITEM_SKINS) / 2;
|
||||
int max_by_vines = get_personal_count(ITEM_VINES);
|
||||
int max_craft = max_by_skins;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_POUCHES);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_SKINS) < 2)
|
||||
missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -411,9 +461,12 @@ void craft_skin_pouch_max() {
|
||||
|
||||
void craft_backpack() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 11) missing += "11 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 5) missing += "5 vines ";
|
||||
if (get_total_pouch_count() < 4) missing += "4 skin pouches ";
|
||||
if (get_personal_count(ITEM_SKINS) < 11)
|
||||
missing += "11 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 5)
|
||||
missing += "5 vines ";
|
||||
if (get_total_pouch_count() < 4)
|
||||
missing += "4 skin pouches ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_BACKPACKS) >= get_personal_stack_limit()) {
|
||||
@@ -441,17 +494,23 @@ void craft_backpack_max() {
|
||||
int max_by_vines = get_personal_count(ITEM_VINES) / 5;
|
||||
int max_by_pouches = get_total_pouch_count() / 4;
|
||||
int max_craft = max_by_skins;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_pouches < max_craft) max_craft = max_by_pouches;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
if (max_by_pouches < max_craft)
|
||||
max_craft = max_by_pouches;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_BACKPACKS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 11) missing += "11 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 5) missing += "5 vines ";
|
||||
if (get_total_pouch_count() < 4) missing += "4 skin pouches ";
|
||||
if (get_personal_count(ITEM_SKINS) < 11)
|
||||
missing += "11 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 5)
|
||||
missing += "5 vines ";
|
||||
if (get_total_pouch_count() < 4)
|
||||
missing += "4 skin pouches ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,12 @@
|
||||
void run_materials_menu() {
|
||||
int selection = 0;
|
||||
string[] options = {
|
||||
"Butcher Game [Requires Game, Knife, Fire nearby]",
|
||||
"Smoke Fish (1 Fish, 1 Stick) [Requires Fire nearby]",
|
||||
"Arrows (2 Sticks, 4 Feathers, 2 Stones) [Requires Quiver]",
|
||||
"Bowstring (3 Sinew) [Requires Fire nearby]",
|
||||
"Incense (6 Sticks, 2 Vines, 1 Reed) [Requires Altar]"
|
||||
};
|
||||
"Butcher Game [Requires Game, Knife, Fire nearby]", "Smoke Fish (1 Fish, 1 Stick) [Requires Fire nearby]",
|
||||
"Arrows (2 Sticks, 4 Feathers, 2 Stones) [Requires Quiver]", "Bowstring (3 Sinew) [Requires Fire nearby]",
|
||||
"Incense (6 Sticks, 2 Vines, 1 Reed) [Requires Altar]"};
|
||||
speak_with_history("Materials. " + options[selection], true);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -23,34 +20,46 @@ void run_materials_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= options.length()) selection = 0;
|
||||
if (selection >= options.length())
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = options.length() - 1;
|
||||
if (selection < 0)
|
||||
selection = options.length() - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
play_menu_select_sound();
|
||||
if (selection == 0) butcher_small_game();
|
||||
else if (selection == 1) craft_smoke_fish();
|
||||
else if (selection == 2) craft_arrows();
|
||||
else if (selection == 3) craft_bowstring();
|
||||
else if (selection == 4) craft_incense();
|
||||
if (selection == 0)
|
||||
butcher_small_game();
|
||||
else if (selection == 1)
|
||||
craft_smoke_fish();
|
||||
else if (selection == 2)
|
||||
craft_arrows();
|
||||
else if (selection == 3)
|
||||
craft_bowstring();
|
||||
else if (selection == 4)
|
||||
craft_incense();
|
||||
break;
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_TAB)) {
|
||||
play_menu_select_sound();
|
||||
if (selection == 0) butcher_small_game_max();
|
||||
else if (selection == 1) craft_smoke_fish_max();
|
||||
else if (selection == 2) craft_arrows_max();
|
||||
else if (selection == 3) craft_bowstring_max();
|
||||
else if (selection == 4) craft_incense_max();
|
||||
if (selection == 0)
|
||||
butcher_small_game_max();
|
||||
else if (selection == 1)
|
||||
craft_smoke_fish_max();
|
||||
else if (selection == 2)
|
||||
craft_arrows_max();
|
||||
else if (selection == 3)
|
||||
craft_bowstring_max();
|
||||
else if (selection == 4)
|
||||
craft_incense_max();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -70,9 +79,12 @@ void craft_arrows() {
|
||||
}
|
||||
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < 2) missing += "2 sticks ";
|
||||
if (get_personal_count(ITEM_FEATHERS) < 4) missing += "4 feathers ";
|
||||
if (get_personal_count(ITEM_STONES) < 2) missing += "2 stones ";
|
||||
if (get_personal_count(ITEM_STICKS) < 2)
|
||||
missing += "2 sticks ";
|
||||
if (get_personal_count(ITEM_FEATHERS) < 4)
|
||||
missing += "4 feathers ";
|
||||
if (get_personal_count(ITEM_STONES) < 2)
|
||||
missing += "2 stones ";
|
||||
|
||||
if (missing == "") {
|
||||
simulate_crafting(8);
|
||||
@@ -104,15 +116,21 @@ void craft_arrows_max() {
|
||||
int maxByFeathers = get_personal_count(ITEM_FEATHERS) / 4;
|
||||
int maxByStones = get_personal_count(ITEM_STONES) / 2;
|
||||
int maxCraft = maxBySticks;
|
||||
if (maxByFeathers < maxCraft) maxCraft = maxByFeathers;
|
||||
if (maxByStones < maxCraft) maxCraft = maxByStones;
|
||||
if (maxByCapacity < maxCraft) maxCraft = maxByCapacity;
|
||||
if (maxByFeathers < maxCraft)
|
||||
maxCraft = maxByFeathers;
|
||||
if (maxByStones < maxCraft)
|
||||
maxCraft = maxByStones;
|
||||
if (maxByCapacity < maxCraft)
|
||||
maxCraft = maxByCapacity;
|
||||
|
||||
if (maxCraft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < 2) missing += "2 sticks ";
|
||||
if (get_personal_count(ITEM_FEATHERS) < 4) missing += "4 feathers ";
|
||||
if (get_personal_count(ITEM_STONES) < 2) missing += "2 stones ";
|
||||
if (get_personal_count(ITEM_STICKS) < 2)
|
||||
missing += "2 sticks ";
|
||||
if (get_personal_count(ITEM_FEATHERS) < 4)
|
||||
missing += "4 feathers ";
|
||||
if (get_personal_count(ITEM_STONES) < 2)
|
||||
missing += "2 stones ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -128,14 +146,15 @@ void craft_arrows_max() {
|
||||
}
|
||||
|
||||
void craft_bowstring() {
|
||||
WorldFire@ fire = get_fire_within_range(x, 3);
|
||||
WorldFire @fire = get_fire_within_range(x, 3);
|
||||
if (fire == null) {
|
||||
speak_with_history("You need a fire within 3 tiles to make bowstring.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SINEW) < 3) missing += "3 sinew ";
|
||||
if (get_personal_count(ITEM_SINEW) < 3)
|
||||
missing += "3 sinew ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_BOWSTRINGS) >= get_personal_stack_limit()) {
|
||||
@@ -152,7 +171,7 @@ void craft_bowstring() {
|
||||
}
|
||||
|
||||
void craft_bowstring_max() {
|
||||
WorldFire@ fire = get_fire_within_range(x, 3);
|
||||
WorldFire @fire = get_fire_within_range(x, 3);
|
||||
if (fire == null) {
|
||||
speak_with_history("You need a fire within 3 tiles to make bowstring.", true);
|
||||
return;
|
||||
@@ -167,7 +186,8 @@ void craft_bowstring_max() {
|
||||
int max_craft = max_by_sinew;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_BOWSTRINGS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
speak_with_history("Missing: 3 sinew", true);
|
||||
@@ -189,9 +209,12 @@ void craft_incense() {
|
||||
}
|
||||
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < INCENSE_STICK_COST) missing += INCENSE_STICK_COST + " sticks ";
|
||||
if (get_personal_count(ITEM_VINES) < INCENSE_VINE_COST) missing += INCENSE_VINE_COST + " vines ";
|
||||
if (get_personal_count(ITEM_REEDS) < INCENSE_REED_COST) missing += INCENSE_REED_COST + " reed ";
|
||||
if (get_personal_count(ITEM_STICKS) < INCENSE_STICK_COST)
|
||||
missing += INCENSE_STICK_COST + " sticks ";
|
||||
if (get_personal_count(ITEM_VINES) < INCENSE_VINE_COST)
|
||||
missing += INCENSE_VINE_COST + " vines ";
|
||||
if (get_personal_count(ITEM_REEDS) < INCENSE_REED_COST)
|
||||
missing += INCENSE_REED_COST + " reed ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_INCENSE) >= get_personal_stack_limit()) {
|
||||
@@ -224,22 +247,29 @@ void craft_incense_max() {
|
||||
int max_by_vines = get_personal_count(ITEM_VINES) / INCENSE_VINE_COST;
|
||||
int max_by_reeds = get_personal_count(ITEM_REEDS) / INCENSE_REED_COST;
|
||||
int max_craft = max_by_sticks;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_reeds < max_craft) max_craft = max_by_reeds;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
if (max_by_reeds < max_craft)
|
||||
max_craft = max_by_reeds;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_INCENSE);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < INCENSE_STICK_COST) missing += INCENSE_STICK_COST + " sticks ";
|
||||
if (get_personal_count(ITEM_VINES) < INCENSE_VINE_COST) missing += INCENSE_VINE_COST + " vines ";
|
||||
if (get_personal_count(ITEM_REEDS) < INCENSE_REED_COST) missing += INCENSE_REED_COST + " reed ";
|
||||
if (get_personal_count(ITEM_STICKS) < INCENSE_STICK_COST)
|
||||
missing += INCENSE_STICK_COST + " sticks ";
|
||||
if (get_personal_count(ITEM_VINES) < INCENSE_VINE_COST)
|
||||
missing += INCENSE_VINE_COST + " vines ";
|
||||
if (get_personal_count(ITEM_REEDS) < INCENSE_REED_COST)
|
||||
missing += INCENSE_REED_COST + " reed ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
|
||||
int total_cost = (max_craft * INCENSE_STICK_COST) + (max_craft * INCENSE_VINE_COST) + (max_craft * INCENSE_REED_COST);
|
||||
int total_cost =
|
||||
(max_craft * INCENSE_STICK_COST) + (max_craft * INCENSE_VINE_COST) + (max_craft * INCENSE_REED_COST);
|
||||
simulate_crafting(total_cost);
|
||||
add_personal_count(ITEM_STICKS, -(max_craft * INCENSE_STICK_COST));
|
||||
add_personal_count(ITEM_VINES, -(max_craft * INCENSE_VINE_COST));
|
||||
@@ -249,15 +279,17 @@ void craft_incense_max() {
|
||||
}
|
||||
|
||||
void craft_smoke_fish() {
|
||||
WorldFire@ fire = get_fire_within_range(x, 3);
|
||||
WorldFire @fire = get_fire_within_range(x, 3);
|
||||
if (fire == null) {
|
||||
speak_with_history("You need a fire within 3 tiles to smoke fish.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_FISH) < 1) missing += "1 fish ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_FISH) < 1)
|
||||
missing += "1 fish ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
|
||||
if (missing == "") {
|
||||
int weight = (personal_fish_weights.length() > 0) ? personal_fish_weights[0] : get_default_fish_weight();
|
||||
@@ -279,7 +311,7 @@ void craft_smoke_fish() {
|
||||
}
|
||||
|
||||
void craft_smoke_fish_max() {
|
||||
WorldFire@ fire = get_fire_within_range(x, 3);
|
||||
WorldFire @fire = get_fire_within_range(x, 3);
|
||||
if (fire == null) {
|
||||
speak_with_history("You need a fire within 3 tiles to smoke fish.", true);
|
||||
return;
|
||||
@@ -288,12 +320,15 @@ void craft_smoke_fish_max() {
|
||||
int max_by_fish = get_personal_count(ITEM_FISH);
|
||||
int max_by_sticks = get_personal_count(ITEM_STICKS);
|
||||
int max_craft = max_by_fish;
|
||||
if (max_by_sticks < max_craft) max_craft = max_by_sticks;
|
||||
if (max_by_sticks < max_craft)
|
||||
max_craft = max_by_sticks;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_FISH) < 1) missing += "1 fish ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_FISH) < 1)
|
||||
missing += "1 fish ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -309,7 +344,8 @@ void craft_smoke_fish_max() {
|
||||
for (int i = 0; i < max_craft; i++) {
|
||||
int weight = (i < int(personal_fish_weights.length())) ? personal_fish_weights[i] : get_default_fish_weight();
|
||||
int yield = get_smoked_fish_yield(weight);
|
||||
if (total_yield + yield > space) break;
|
||||
if (total_yield + yield > space)
|
||||
break;
|
||||
total_yield += yield;
|
||||
fish_to_smoke++;
|
||||
}
|
||||
@@ -335,13 +371,15 @@ void butcher_small_game() {
|
||||
string missing = "";
|
||||
|
||||
// Check for knife
|
||||
if (get_personal_count(ITEM_KNIVES) < 1) missing += "Stone Knife ";
|
||||
if (get_personal_count(ITEM_KNIVES) < 1)
|
||||
missing += "Stone Knife ";
|
||||
|
||||
// Check for small game or boar
|
||||
if (get_personal_count(ITEM_SMALL_GAME) < 1 && get_personal_count(ITEM_BOAR_CARCASSES) < 1) missing += "Game ";
|
||||
if (get_personal_count(ITEM_SMALL_GAME) < 1 && get_personal_count(ITEM_BOAR_CARCASSES) < 1)
|
||||
missing += "Game ";
|
||||
|
||||
// Check for fire within 3 tiles (can hear it)
|
||||
WorldFire@ fire = get_fire_within_range(x, 3);
|
||||
WorldFire @fire = get_fire_within_range(x, 3);
|
||||
if (fire == null) {
|
||||
speak_with_history("You need a fire within 3 tiles to butcher.", true);
|
||||
return;
|
||||
@@ -411,7 +449,7 @@ void butcher_small_game_max() {
|
||||
}
|
||||
|
||||
// Check for fire within 3 tiles (can hear it)
|
||||
WorldFire@ fire = get_fire_within_range(x, 3);
|
||||
WorldFire @fire = get_fire_within_range(x, 3);
|
||||
if (fire == null) {
|
||||
speak_with_history("You need a fire within 3 tiles to butcher.", true);
|
||||
return;
|
||||
@@ -435,8 +473,10 @@ void butcher_small_game_max() {
|
||||
|
||||
// Determine limiting factor
|
||||
int max_craft = total_game;
|
||||
if (meat_space < max_craft) max_craft = meat_space;
|
||||
if (skins_space < max_craft) max_craft = skins_space;
|
||||
if (meat_space < max_craft)
|
||||
max_craft = meat_space;
|
||||
if (skins_space < max_craft)
|
||||
max_craft = skins_space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
speak_with_history("No space for outputs.", true);
|
||||
@@ -468,8 +508,10 @@ void butcher_small_game_max() {
|
||||
game_type = personal_small_game_types[0];
|
||||
personal_small_game_types.remove_at(0);
|
||||
add_personal_count(ITEM_SMALL_GAME, -1);
|
||||
if (game_type == "goose") geese_count++;
|
||||
if (game_type == "turkey") turkey_count++;
|
||||
if (game_type == "goose")
|
||||
geese_count++;
|
||||
if (game_type == "turkey")
|
||||
turkey_count++;
|
||||
}
|
||||
|
||||
if (game_type == "goose") {
|
||||
@@ -498,10 +540,14 @@ void butcher_small_game_max() {
|
||||
|
||||
// Build result message
|
||||
string result = "Butchered " + max_craft + " game. Got " + total_meat + " meat";
|
||||
if (total_skins > 0) result += ", " + total_skins + " skins";
|
||||
if (total_feathers > 0) result += ", feathers";
|
||||
if (total_down > 0) result += ", and down";
|
||||
if (total_sinew > 0) result += ", and " + total_sinew + " sinew";
|
||||
if (total_skins > 0)
|
||||
result += ", " + total_skins + " skins";
|
||||
if (total_feathers > 0)
|
||||
result += ", feathers";
|
||||
if (total_down > 0)
|
||||
result += ", and down";
|
||||
if (total_sinew > 0)
|
||||
result += ", and " + total_sinew + " sinew";
|
||||
result += ".";
|
||||
|
||||
speak_with_history(result, true);
|
||||
|
||||
+152
-65
@@ -4,68 +4,140 @@
|
||||
|
||||
// Get the base equipment name without any rune prefix
|
||||
string get_base_equipment_name(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR) return "Spear";
|
||||
if (equip_type == EQUIP_AXE) return "Stone Axe";
|
||||
if (equip_type == EQUIP_SLING) return "Sling";
|
||||
if (equip_type == EQUIP_BOW) return "Bow";
|
||||
if (equip_type == EQUIP_HAT) return "Skin Hat";
|
||||
if (equip_type == EQUIP_GLOVES) return "Skin Gloves";
|
||||
if (equip_type == EQUIP_PANTS) return "Skin Pants";
|
||||
if (equip_type == EQUIP_TUNIC) return "Skin Tunic";
|
||||
if (equip_type == EQUIP_MOCCASINS) return "Moccasins";
|
||||
if (equip_type == EQUIP_POUCH) return "Skin Pouch";
|
||||
if (equip_type == EQUIP_BACKPACK) return "Backpack";
|
||||
if (equip_type == EQUIP_FISHING_POLE) return "Fishing Pole";
|
||||
if (equip_type == EQUIP_SPEAR)
|
||||
return "Spear";
|
||||
if (equip_type == EQUIP_AXE)
|
||||
return "Stone Axe";
|
||||
if (equip_type == EQUIP_SLING)
|
||||
return "Sling";
|
||||
if (equip_type == EQUIP_BOW)
|
||||
return "Bow";
|
||||
if (equip_type == EQUIP_HAT)
|
||||
return "Skin Hat";
|
||||
if (equip_type == EQUIP_GLOVES)
|
||||
return "Skin Gloves";
|
||||
if (equip_type == EQUIP_PANTS)
|
||||
return "Skin Pants";
|
||||
if (equip_type == EQUIP_TUNIC)
|
||||
return "Skin Tunic";
|
||||
if (equip_type == EQUIP_MOCCASINS)
|
||||
return "Moccasins";
|
||||
if (equip_type == EQUIP_POUCH)
|
||||
return "Skin Pouch";
|
||||
if (equip_type == EQUIP_BACKPACK)
|
||||
return "Backpack";
|
||||
if (equip_type == EQUIP_FISHING_POLE)
|
||||
return "Fishing Pole";
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
string get_base_equipment_name_plural(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR) return "Spears";
|
||||
if (equip_type == EQUIP_AXE) return "Stone Axes";
|
||||
if (equip_type == EQUIP_SLING) return "Slings";
|
||||
if (equip_type == EQUIP_BOW) return "Bows";
|
||||
if (equip_type == EQUIP_HAT) return "Skin Hats";
|
||||
if (equip_type == EQUIP_GLOVES) return "Skin Gloves";
|
||||
if (equip_type == EQUIP_PANTS) return "Skin Pants";
|
||||
if (equip_type == EQUIP_TUNIC) return "Skin Tunics";
|
||||
if (equip_type == EQUIP_MOCCASINS) return "Moccasins";
|
||||
if (equip_type == EQUIP_POUCH) return "Skin Pouches";
|
||||
if (equip_type == EQUIP_BACKPACK) return "Backpacks";
|
||||
if (equip_type == EQUIP_FISHING_POLE) return "Fishing Poles";
|
||||
if (equip_type == EQUIP_SPEAR)
|
||||
return "Spears";
|
||||
if (equip_type == EQUIP_AXE)
|
||||
return "Stone Axes";
|
||||
if (equip_type == EQUIP_SLING)
|
||||
return "Slings";
|
||||
if (equip_type == EQUIP_BOW)
|
||||
return "Bows";
|
||||
if (equip_type == EQUIP_HAT)
|
||||
return "Skin Hats";
|
||||
if (equip_type == EQUIP_GLOVES)
|
||||
return "Skin Gloves";
|
||||
if (equip_type == EQUIP_PANTS)
|
||||
return "Skin Pants";
|
||||
if (equip_type == EQUIP_TUNIC)
|
||||
return "Skin Tunics";
|
||||
if (equip_type == EQUIP_MOCCASINS)
|
||||
return "Moccasins";
|
||||
if (equip_type == EQUIP_POUCH)
|
||||
return "Skin Pouches";
|
||||
if (equip_type == EQUIP_BACKPACK)
|
||||
return "Backpacks";
|
||||
if (equip_type == EQUIP_FISHING_POLE)
|
||||
return "Fishing Poles";
|
||||
return "Items";
|
||||
}
|
||||
|
||||
// Get inventory count for an equipment type
|
||||
int get_unruned_equipment_count(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR) return get_personal_count(ITEM_SPEARS);
|
||||
if (equip_type == EQUIP_AXE) return get_personal_count(ITEM_AXES);
|
||||
if (equip_type == EQUIP_SLING) return get_personal_count(ITEM_SLINGS);
|
||||
if (equip_type == EQUIP_BOW) return get_personal_count(ITEM_BOWS);
|
||||
if (equip_type == EQUIP_HAT) return get_personal_count(ITEM_SKIN_HATS);
|
||||
if (equip_type == EQUIP_GLOVES) return get_personal_count(ITEM_SKIN_GLOVES);
|
||||
if (equip_type == EQUIP_PANTS) return get_personal_count(ITEM_SKIN_PANTS);
|
||||
if (equip_type == EQUIP_TUNIC) return get_personal_count(ITEM_SKIN_TUNICS);
|
||||
if (equip_type == EQUIP_MOCCASINS) return get_personal_count(ITEM_MOCCASINS);
|
||||
if (equip_type == EQUIP_POUCH) return get_personal_count(ITEM_SKIN_POUCHES);
|
||||
if (equip_type == EQUIP_BACKPACK) return get_personal_count(ITEM_BACKPACKS);
|
||||
if (equip_type == EQUIP_FISHING_POLE) return get_personal_count(ITEM_FISHING_POLES);
|
||||
if (equip_type == EQUIP_SPEAR)
|
||||
return get_personal_count(ITEM_SPEARS);
|
||||
if (equip_type == EQUIP_AXE)
|
||||
return get_personal_count(ITEM_AXES);
|
||||
if (equip_type == EQUIP_SLING)
|
||||
return get_personal_count(ITEM_SLINGS);
|
||||
if (equip_type == EQUIP_BOW)
|
||||
return get_personal_count(ITEM_BOWS);
|
||||
if (equip_type == EQUIP_HAT)
|
||||
return get_personal_count(ITEM_SKIN_HATS);
|
||||
if (equip_type == EQUIP_GLOVES)
|
||||
return get_personal_count(ITEM_SKIN_GLOVES);
|
||||
if (equip_type == EQUIP_PANTS)
|
||||
return get_personal_count(ITEM_SKIN_PANTS);
|
||||
if (equip_type == EQUIP_TUNIC)
|
||||
return get_personal_count(ITEM_SKIN_TUNICS);
|
||||
if (equip_type == EQUIP_MOCCASINS)
|
||||
return get_personal_count(ITEM_MOCCASINS);
|
||||
if (equip_type == EQUIP_POUCH)
|
||||
return get_personal_count(ITEM_SKIN_POUCHES);
|
||||
if (equip_type == EQUIP_BACKPACK)
|
||||
return get_personal_count(ITEM_BACKPACKS);
|
||||
if (equip_type == EQUIP_FISHING_POLE)
|
||||
return get_personal_count(ITEM_FISHING_POLES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Decrement inventory for an equipment type
|
||||
void decrement_unruned_equipment(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR) { add_personal_count(ITEM_SPEARS, -1); return; }
|
||||
if (equip_type == EQUIP_AXE) { add_personal_count(ITEM_AXES, -1); return; }
|
||||
if (equip_type == EQUIP_SLING) { add_personal_count(ITEM_SLINGS, -1); return; }
|
||||
if (equip_type == EQUIP_BOW) { add_personal_count(ITEM_BOWS, -1); return; }
|
||||
if (equip_type == EQUIP_HAT) { add_personal_count(ITEM_SKIN_HATS, -1); return; }
|
||||
if (equip_type == EQUIP_GLOVES) { add_personal_count(ITEM_SKIN_GLOVES, -1); return; }
|
||||
if (equip_type == EQUIP_PANTS) { add_personal_count(ITEM_SKIN_PANTS, -1); return; }
|
||||
if (equip_type == EQUIP_TUNIC) { add_personal_count(ITEM_SKIN_TUNICS, -1); return; }
|
||||
if (equip_type == EQUIP_MOCCASINS) { add_personal_count(ITEM_MOCCASINS, -1); return; }
|
||||
if (equip_type == EQUIP_POUCH) { add_personal_count(ITEM_SKIN_POUCHES, -1); return; }
|
||||
if (equip_type == EQUIP_BACKPACK) { add_personal_count(ITEM_BACKPACKS, -1); return; }
|
||||
if (equip_type == EQUIP_FISHING_POLE) { add_personal_count(ITEM_FISHING_POLES, -1); return; }
|
||||
if (equip_type == EQUIP_SPEAR) {
|
||||
add_personal_count(ITEM_SPEARS, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_AXE) {
|
||||
add_personal_count(ITEM_AXES, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_SLING) {
|
||||
add_personal_count(ITEM_SLINGS, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_BOW) {
|
||||
add_personal_count(ITEM_BOWS, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_HAT) {
|
||||
add_personal_count(ITEM_SKIN_HATS, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_GLOVES) {
|
||||
add_personal_count(ITEM_SKIN_GLOVES, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_PANTS) {
|
||||
add_personal_count(ITEM_SKIN_PANTS, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_TUNIC) {
|
||||
add_personal_count(ITEM_SKIN_TUNICS, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_MOCCASINS) {
|
||||
add_personal_count(ITEM_MOCCASINS, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_POUCH) {
|
||||
add_personal_count(ITEM_SKIN_POUCHES, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_BACKPACK) {
|
||||
add_personal_count(ITEM_BACKPACKS, -1);
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_FISHING_POLE) {
|
||||
add_personal_count(ITEM_FISHING_POLES, -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void run_runes_menu() {
|
||||
@@ -95,7 +167,7 @@ void run_runes_menu() {
|
||||
int selection = 0;
|
||||
speak_with_history("Runes. " + rune_options[selection], true);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -108,14 +180,16 @@ void run_runes_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(rune_options.length())) selection = 0;
|
||||
if (selection >= int(rune_options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(rune_options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(rune_options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(rune_options.length()) - 1;
|
||||
speak_with_history(rune_options[selection], true);
|
||||
}
|
||||
|
||||
@@ -150,9 +224,10 @@ void run_rune_equipment_menu(int rune_type) {
|
||||
}
|
||||
|
||||
int selection = 0;
|
||||
speak_with_history("Select equipment to engrave with " + get_rune_name(rune_type) + ". " + equipment_options[selection], true);
|
||||
speak_with_history(
|
||||
"Select equipment to engrave with " + get_rune_name(rune_type) + ". " + equipment_options[selection], true);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -165,14 +240,16 @@ void run_rune_equipment_menu(int rune_type) {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(equipment_options.length())) selection = 0;
|
||||
if (selection >= int(equipment_options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(equipment_options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(equipment_options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(equipment_options.length()) - 1;
|
||||
speak_with_history(equipment_options[selection], true);
|
||||
}
|
||||
|
||||
@@ -195,9 +272,12 @@ void run_rune_equipment_menu(int rune_type) {
|
||||
void engrave_rune(int equip_type, int rune_type) {
|
||||
// Validate requirements
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_KNIVES) < 1) missing += "Stone Knife ";
|
||||
if (get_personal_count(ITEM_CLAY) < 1) missing += "1 clay ";
|
||||
if (favor < 1.0) missing += "1 favor ";
|
||||
if (get_personal_count(ITEM_KNIVES) < 1)
|
||||
missing += "Stone Knife ";
|
||||
if (get_personal_count(ITEM_CLAY) < 1)
|
||||
missing += "1 clay ";
|
||||
if (favor < 1.0)
|
||||
missing += "1 favor ";
|
||||
|
||||
// Check equipment is still available
|
||||
if (get_unruned_equipment_count(equip_type) < 1) {
|
||||
@@ -229,7 +309,8 @@ void engrave_rune(int equip_type, int rune_type) {
|
||||
void engrave_rune_max(int equip_type, int rune_type) {
|
||||
// Validate requirements
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_KNIVES) < 1) missing += "Stone Knife ";
|
||||
if (get_personal_count(ITEM_KNIVES) < 1)
|
||||
missing += "Stone Knife ";
|
||||
|
||||
int unruned_count = get_unruned_equipment_count(equip_type);
|
||||
if (unruned_count < 1) {
|
||||
@@ -240,8 +321,10 @@ void engrave_rune_max(int equip_type, int rune_type) {
|
||||
int clay_count = get_personal_count(ITEM_CLAY);
|
||||
int favor_count = int(favor);
|
||||
int max_craft = unruned_count;
|
||||
if (clay_count < max_craft) max_craft = clay_count;
|
||||
if (favor_count < max_craft) max_craft = favor_count;
|
||||
if (clay_count < max_craft)
|
||||
max_craft = clay_count;
|
||||
if (favor_count < max_craft)
|
||||
max_craft = favor_count;
|
||||
|
||||
if (missing != "") {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
@@ -249,9 +332,12 @@ void engrave_rune_max(int equip_type, int rune_type) {
|
||||
}
|
||||
|
||||
if (max_craft <= 0) {
|
||||
if (clay_count < 1) missing += "1 clay ";
|
||||
if (favor < 1.0) missing += "1 favor ";
|
||||
if (missing == "") missing = "resources";
|
||||
if (clay_count < 1)
|
||||
missing += "1 clay ";
|
||||
if (favor < 1.0)
|
||||
missing += "1 favor ";
|
||||
if (missing == "")
|
||||
missing = "resources";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -267,6 +353,7 @@ void engrave_rune_max(int equip_type, int rune_type) {
|
||||
|
||||
simulate_crafting(6 * max_craft);
|
||||
|
||||
string item_name = (max_craft == 1) ? get_base_equipment_name(equip_type) : get_base_equipment_name_plural(equip_type);
|
||||
string item_name =
|
||||
(max_craft == 1) ? get_base_equipment_name(equip_type) : get_base_equipment_name_plural(equip_type);
|
||||
speak_with_history("Engraved " + max_craft + " " + item_name + " with " + get_rune_name(rune_type) + ".", true);
|
||||
}
|
||||
|
||||
+133
-71
@@ -1,8 +1,7 @@
|
||||
// Crafting tools
|
||||
void run_tools_menu() {
|
||||
int selection = 0;
|
||||
string[] options = {
|
||||
"Stone Knife (2 Stones)",
|
||||
string[] options = {"Stone Knife (2 Stones)",
|
||||
"Snare (1 Stick, 2 Vines)",
|
||||
"Stone Axe (1 Stick, 1 Vine, 2 Stones) [Requires Knife]",
|
||||
"Fishing Pole (1 Stick, 2 Vines)",
|
||||
@@ -10,11 +9,10 @@ void run_tools_menu() {
|
||||
"Quiver (2 Skins, 2 Vines)",
|
||||
"Canoe (4 Logs, 11 Sticks, 11 Vines, 6 Skins, 2 Rope, 6 Reeds)",
|
||||
"Reed Basket (3 Reeds)",
|
||||
"Clay Pot (3 Clay)"
|
||||
};
|
||||
"Clay Pot (3 Clay)"};
|
||||
speak_with_history("Tools. " + options[selection], true);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -27,42 +25,62 @@ void run_tools_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= options.length()) selection = 0;
|
||||
if (selection >= options.length())
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = options.length() - 1;
|
||||
if (selection < 0)
|
||||
selection = options.length() - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
play_menu_select_sound();
|
||||
if (selection == 0) craft_knife();
|
||||
else if (selection == 1) craft_snare();
|
||||
else if (selection == 2) craft_axe();
|
||||
else if (selection == 3) craft_fishing_pole();
|
||||
else if (selection == 4) craft_rope();
|
||||
else if (selection == 5) craft_quiver();
|
||||
else if (selection == 6) craft_canoe();
|
||||
else if (selection == 7) craft_reed_basket();
|
||||
else if (selection == 8) craft_clay_pot();
|
||||
if (selection == 0)
|
||||
craft_knife();
|
||||
else if (selection == 1)
|
||||
craft_snare();
|
||||
else if (selection == 2)
|
||||
craft_axe();
|
||||
else if (selection == 3)
|
||||
craft_fishing_pole();
|
||||
else if (selection == 4)
|
||||
craft_rope();
|
||||
else if (selection == 5)
|
||||
craft_quiver();
|
||||
else if (selection == 6)
|
||||
craft_canoe();
|
||||
else if (selection == 7)
|
||||
craft_reed_basket();
|
||||
else if (selection == 8)
|
||||
craft_clay_pot();
|
||||
break;
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_TAB)) {
|
||||
play_menu_select_sound();
|
||||
if (selection == 0) craft_knife_max();
|
||||
else if (selection == 1) craft_snare_max();
|
||||
else if (selection == 2) craft_axe_max();
|
||||
else if (selection == 3) craft_fishing_pole_max();
|
||||
else if (selection == 4) craft_rope_max();
|
||||
else if (selection == 5) craft_quiver_max();
|
||||
else if (selection == 6) craft_canoe_max();
|
||||
else if (selection == 7) craft_reed_basket_max();
|
||||
else if (selection == 8) craft_clay_pot_max();
|
||||
if (selection == 0)
|
||||
craft_knife_max();
|
||||
else if (selection == 1)
|
||||
craft_snare_max();
|
||||
else if (selection == 2)
|
||||
craft_axe_max();
|
||||
else if (selection == 3)
|
||||
craft_fishing_pole_max();
|
||||
else if (selection == 4)
|
||||
craft_rope_max();
|
||||
else if (selection == 5)
|
||||
craft_quiver_max();
|
||||
else if (selection == 6)
|
||||
craft_canoe_max();
|
||||
else if (selection == 7)
|
||||
craft_reed_basket_max();
|
||||
else if (selection == 8)
|
||||
craft_clay_pot_max();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -70,7 +88,8 @@ void run_tools_menu() {
|
||||
|
||||
void craft_knife() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STONES) < 2) missing += "2 stones ";
|
||||
if (get_personal_count(ITEM_STONES) < 2)
|
||||
missing += "2 stones ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_KNIVES) >= get_personal_stack_limit()) {
|
||||
@@ -94,7 +113,8 @@ void craft_knife_max() {
|
||||
|
||||
int max_possible = get_personal_count(ITEM_STONES) / 2;
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_KNIVES);
|
||||
if (max_possible > space) max_possible = space;
|
||||
if (max_possible > space)
|
||||
max_possible = space;
|
||||
|
||||
if (max_possible <= 0) {
|
||||
speak_with_history("Missing: 2 stones", true);
|
||||
@@ -111,8 +131,10 @@ void craft_knife_max() {
|
||||
|
||||
void craft_snare() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SNARES) >= get_personal_stack_limit()) {
|
||||
@@ -138,15 +160,19 @@ void craft_snare_max() {
|
||||
int max_by_sticks = get_personal_count(ITEM_STICKS);
|
||||
int max_by_vines = get_personal_count(ITEM_VINES) / 2;
|
||||
int max_craft = max_by_sticks;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_SNARES);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -162,8 +188,10 @@ void craft_snare_max() {
|
||||
|
||||
void craft_fishing_pole() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_FISHING_POLES) >= get_personal_stack_limit()) {
|
||||
@@ -189,15 +217,19 @@ void craft_fishing_pole_max() {
|
||||
int max_by_sticks = get_personal_count(ITEM_STICKS);
|
||||
int max_by_vines = get_personal_count(ITEM_VINES) / 2;
|
||||
int max_craft = max_by_sticks;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_FISHING_POLES);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -213,7 +245,8 @@ void craft_fishing_pole_max() {
|
||||
|
||||
void craft_rope() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_VINES) < 3) missing += "3 vines ";
|
||||
if (get_personal_count(ITEM_VINES) < 3)
|
||||
missing += "3 vines ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_ROPES) >= get_personal_stack_limit()) {
|
||||
@@ -238,7 +271,8 @@ void craft_rope_max() {
|
||||
int max_craft = get_personal_count(ITEM_VINES) / 3;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_ROPES);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
speak_with_history("Missing: 3 vines", true);
|
||||
@@ -255,8 +289,10 @@ void craft_rope_max() {
|
||||
|
||||
void craft_quiver() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 2)
|
||||
missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_QUIVERS) >= get_personal_stack_limit()) {
|
||||
@@ -282,15 +318,19 @@ void craft_quiver_max() {
|
||||
int maxBySkins = get_personal_count(ITEM_SKINS) / 2;
|
||||
int maxByVines = get_personal_count(ITEM_VINES) / 2;
|
||||
int maxCraft = maxBySkins;
|
||||
if (maxByVines < maxCraft) maxCraft = maxByVines;
|
||||
if (maxByVines < maxCraft)
|
||||
maxCraft = maxByVines;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_QUIVERS);
|
||||
if (maxCraft > space) maxCraft = space;
|
||||
if (maxCraft > space)
|
||||
maxCraft = space;
|
||||
|
||||
if (maxCraft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 2)
|
||||
missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -306,12 +346,18 @@ void craft_quiver_max() {
|
||||
|
||||
void craft_canoe() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_LOGS) < 4) missing += "4 logs ";
|
||||
if (get_personal_count(ITEM_STICKS) < 11) missing += "11 sticks ";
|
||||
if (get_personal_count(ITEM_VINES) < 11) missing += "11 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_ROPES) < 2) missing += "2 rope ";
|
||||
if (get_personal_count(ITEM_REEDS) < 6) missing += "6 reeds ";
|
||||
if (get_personal_count(ITEM_LOGS) < 4)
|
||||
missing += "4 logs ";
|
||||
if (get_personal_count(ITEM_STICKS) < 11)
|
||||
missing += "11 sticks ";
|
||||
if (get_personal_count(ITEM_VINES) < 11)
|
||||
missing += "11 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 6)
|
||||
missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_ROPES) < 2)
|
||||
missing += "2 rope ";
|
||||
if (get_personal_count(ITEM_REEDS) < 6)
|
||||
missing += "6 reeds ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_CANOES) >= get_personal_stack_limit()) {
|
||||
@@ -345,23 +391,35 @@ void craft_canoe_max() {
|
||||
int maxByRopes = get_personal_count(ITEM_ROPES) / 2;
|
||||
int maxByReeds = get_personal_count(ITEM_REEDS) / 6;
|
||||
int maxCraft = maxByLogs;
|
||||
if (maxBySticks < maxCraft) maxCraft = maxBySticks;
|
||||
if (maxByVines < maxCraft) maxCraft = maxByVines;
|
||||
if (maxBySkins < maxCraft) maxCraft = maxBySkins;
|
||||
if (maxByRopes < maxCraft) maxCraft = maxByRopes;
|
||||
if (maxByReeds < maxCraft) maxCraft = maxByReeds;
|
||||
if (maxBySticks < maxCraft)
|
||||
maxCraft = maxBySticks;
|
||||
if (maxByVines < maxCraft)
|
||||
maxCraft = maxByVines;
|
||||
if (maxBySkins < maxCraft)
|
||||
maxCraft = maxBySkins;
|
||||
if (maxByRopes < maxCraft)
|
||||
maxCraft = maxByRopes;
|
||||
if (maxByReeds < maxCraft)
|
||||
maxCraft = maxByReeds;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_CANOES);
|
||||
if (maxCraft > space) maxCraft = space;
|
||||
if (maxCraft > space)
|
||||
maxCraft = space;
|
||||
|
||||
if (maxCraft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_LOGS) < 4) missing += "4 logs ";
|
||||
if (get_personal_count(ITEM_STICKS) < 11) missing += "11 sticks ";
|
||||
if (get_personal_count(ITEM_VINES) < 11) missing += "11 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_ROPES) < 2) missing += "2 rope ";
|
||||
if (get_personal_count(ITEM_REEDS) < 6) missing += "6 reeds ";
|
||||
if (get_personal_count(ITEM_LOGS) < 4)
|
||||
missing += "4 logs ";
|
||||
if (get_personal_count(ITEM_STICKS) < 11)
|
||||
missing += "11 sticks ";
|
||||
if (get_personal_count(ITEM_VINES) < 11)
|
||||
missing += "11 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 6)
|
||||
missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_ROPES) < 2)
|
||||
missing += "2 rope ";
|
||||
if (get_personal_count(ITEM_REEDS) < 6)
|
||||
missing += "6 reeds ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -381,7 +439,8 @@ void craft_canoe_max() {
|
||||
|
||||
void craft_reed_basket() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_REEDS) < 3) missing += "3 reeds ";
|
||||
if (get_personal_count(ITEM_REEDS) < 3)
|
||||
missing += "3 reeds ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_REED_BASKETS) >= get_personal_stack_limit()) {
|
||||
@@ -406,7 +465,8 @@ void craft_reed_basket_max() {
|
||||
int max_craft = get_personal_count(ITEM_REEDS) / 3;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_REED_BASKETS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
speak_with_history("Missing: 3 reeds", true);
|
||||
@@ -423,10 +483,11 @@ void craft_reed_basket_max() {
|
||||
|
||||
void craft_clay_pot() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_CLAY) < 3) missing += "3 clay ";
|
||||
if (get_personal_count(ITEM_CLAY) < 3)
|
||||
missing += "3 clay ";
|
||||
|
||||
// Check for fire within 3 tiles (can hear it)
|
||||
WorldFire@ fire = get_fire_within_range(x, 3);
|
||||
WorldFire @fire = get_fire_within_range(x, 3);
|
||||
if (fire == null) {
|
||||
speak_with_history("You need a fire within 3 tiles to craft a clay pot.", true);
|
||||
return;
|
||||
@@ -448,7 +509,7 @@ void craft_clay_pot() {
|
||||
|
||||
void craft_clay_pot_max() {
|
||||
// Check for fire within 3 tiles (can hear it)
|
||||
WorldFire@ fire = get_fire_within_range(x, 3);
|
||||
WorldFire @fire = get_fire_within_range(x, 3);
|
||||
if (fire == null) {
|
||||
speak_with_history("You need a fire within 3 tiles to craft clay pots.", true);
|
||||
return;
|
||||
@@ -462,7 +523,8 @@ void craft_clay_pot_max() {
|
||||
int max_craft = get_personal_count(ITEM_CLAY) / 3;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_CLAY_POTS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
speak_with_history("Missing: 3 clay", true);
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
// Crafting weapons
|
||||
void run_weapons_menu() {
|
||||
int selection = 0;
|
||||
string[] options = {
|
||||
"Spear (1 Stick, 1 Vine, 1 Stone) [Requires Knife]",
|
||||
"Sling (1 Skin, 2 Vines)",
|
||||
"Bow (1 Stick, 1 Bowstring)"
|
||||
};
|
||||
string[] options = {"Spear (1 Stick, 1 Vine, 1 Stone) [Requires Knife]", "Sling (1 Skin, 2 Vines)",
|
||||
"Bow (1 Stick, 1 Bowstring)"};
|
||||
speak_with_history("Weapons. " + options[selection], true);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -21,30 +18,38 @@ void run_weapons_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= options.length()) selection = 0;
|
||||
if (selection >= options.length())
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = options.length() - 1;
|
||||
if (selection < 0)
|
||||
selection = options.length() - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
play_menu_select_sound();
|
||||
if (selection == 0) craft_spear();
|
||||
else if (selection == 1) craft_sling();
|
||||
else if (selection == 2) craft_bow();
|
||||
if (selection == 0)
|
||||
craft_spear();
|
||||
else if (selection == 1)
|
||||
craft_sling();
|
||||
else if (selection == 2)
|
||||
craft_bow();
|
||||
break;
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_TAB)) {
|
||||
play_menu_select_sound();
|
||||
if (selection == 0) craft_spear_max();
|
||||
else if (selection == 1) craft_sling_max();
|
||||
else if (selection == 2) craft_bow_max();
|
||||
if (selection == 0)
|
||||
craft_spear_max();
|
||||
else if (selection == 1)
|
||||
craft_sling_max();
|
||||
else if (selection == 2)
|
||||
craft_bow_max();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -52,10 +57,14 @@ void run_weapons_menu() {
|
||||
|
||||
void craft_spear() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_KNIVES) < 1) missing += "Stone Knife ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_STONES) < 1) missing += "1 stone ";
|
||||
if (get_personal_count(ITEM_KNIVES) < 1)
|
||||
missing += "Stone Knife ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_STONES) < 1)
|
||||
missing += "1 stone ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SPEARS) >= get_personal_stack_limit()) {
|
||||
@@ -87,17 +96,23 @@ void craft_spear_max() {
|
||||
int max_by_vines = get_personal_count(ITEM_VINES);
|
||||
int max_by_stones = get_personal_count(ITEM_STONES);
|
||||
int max_craft = max_by_sticks;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_stones < max_craft) max_craft = max_by_stones;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
if (max_by_stones < max_craft)
|
||||
max_craft = max_by_stones;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_SPEARS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_STONES) < 1) missing += "1 stone ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_STONES) < 1)
|
||||
missing += "1 stone ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -114,8 +129,10 @@ void craft_spear_max() {
|
||||
|
||||
void craft_sling() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 1)
|
||||
missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SLINGS) >= get_personal_stack_limit()) {
|
||||
@@ -141,15 +158,19 @@ void craft_sling_max() {
|
||||
int max_by_skins = get_personal_count(ITEM_SKINS);
|
||||
int max_by_vines = get_personal_count(ITEM_VINES) / 2;
|
||||
int max_craft = max_by_skins;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_SLINGS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 1)
|
||||
missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -165,8 +186,10 @@ void craft_sling_max() {
|
||||
|
||||
void craft_bow() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_BOWSTRINGS) < 1) missing += "1 bowstring ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_BOWSTRINGS) < 1)
|
||||
missing += "1 bowstring ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_BOWS) >= get_personal_stack_limit()) {
|
||||
@@ -192,15 +215,19 @@ void craft_bow_max() {
|
||||
int max_by_sticks = get_personal_count(ITEM_STICKS);
|
||||
int max_by_bowstrings = get_personal_count(ITEM_BOWSTRINGS);
|
||||
int max_craft = max_by_sticks;
|
||||
if (max_by_bowstrings < max_craft) max_craft = max_by_bowstrings;
|
||||
if (max_by_bowstrings < max_craft)
|
||||
max_craft = max_by_bowstrings;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_BOWS);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_BOWSTRINGS) < 1) missing += "1 bowstring ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_BOWSTRINGS) < 1)
|
||||
missing += "1 bowstring ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
@@ -216,10 +243,14 @@ void craft_bow_max() {
|
||||
|
||||
void craft_axe() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_KNIVES) < 1) missing += "Stone Knife ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_STONES) < 2) missing += "2 stones ";
|
||||
if (get_personal_count(ITEM_KNIVES) < 1)
|
||||
missing += "Stone Knife ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_STONES) < 2)
|
||||
missing += "2 stones ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_AXES) >= get_personal_stack_limit()) {
|
||||
@@ -251,17 +282,23 @@ void craft_axe_max() {
|
||||
int max_by_vines = get_personal_count(ITEM_VINES);
|
||||
int max_by_stones = get_personal_count(ITEM_STONES) / 2;
|
||||
int max_craft = max_by_sticks;
|
||||
if (max_by_vines < max_craft) max_craft = max_by_vines;
|
||||
if (max_by_stones < max_craft) max_craft = max_by_stones;
|
||||
if (max_by_vines < max_craft)
|
||||
max_craft = max_by_vines;
|
||||
if (max_by_stones < max_craft)
|
||||
max_craft = max_by_stones;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_AXES);
|
||||
if (max_craft > space) max_craft = space;
|
||||
if (max_craft > space)
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_STONES) < 2) missing += "2 stones ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_STONES) < 2)
|
||||
missing += "2 stones ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ void run_crafting_menu() {
|
||||
}
|
||||
speak_with_history("Crafting menu. " + categories[selection], true);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -48,27 +48,36 @@ void run_crafting_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(categories.length())) selection = 0;
|
||||
if (selection >= int(categories.length()))
|
||||
selection = 0;
|
||||
speak_with_history(categories[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(categories.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(categories.length()) - 1;
|
||||
speak_with_history(categories[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
play_menu_select_sound();
|
||||
int category = category_types[selection];
|
||||
if (category == 0) run_weapons_menu();
|
||||
else if (category == 1) run_tools_menu();
|
||||
else if (category == 2) run_materials_menu();
|
||||
else if (category == 3) run_clothing_menu();
|
||||
else if (category == 4) run_buildings_menu();
|
||||
else if (category == 5) run_barricade_menu();
|
||||
else if (category == 6) run_runes_menu();
|
||||
if (category == 0)
|
||||
run_weapons_menu();
|
||||
else if (category == 1)
|
||||
run_tools_menu();
|
||||
else if (category == 2)
|
||||
run_materials_menu();
|
||||
else if (category == 3)
|
||||
run_clothing_menu();
|
||||
else if (category == 4)
|
||||
run_buildings_menu();
|
||||
else if (category == 5)
|
||||
run_barricade_menu();
|
||||
else if (category == 6)
|
||||
run_runes_menu();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -77,15 +86,15 @@ void run_crafting_menu() {
|
||||
void simulate_crafting(int item_count) {
|
||||
speak_with_history("Crafting...", true);
|
||||
// Nothing should take less than 4.
|
||||
if(item_count < 4) {
|
||||
if (item_count < 4) {
|
||||
item_count = 4;
|
||||
}
|
||||
for(int i = 0; i < item_count; i++) {
|
||||
for (int i = 0; i < item_count; i++) {
|
||||
float pitch = random(85, 115);
|
||||
p.play_stationary_extended("sounds/crafting.ogg", false, 0, 0, 0, pitch);
|
||||
|
||||
timer t;
|
||||
while(t.elapsed < 800) {
|
||||
while (t.elapsed < 800) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
|
||||
+16
-16
@@ -46,15 +46,16 @@ const int CREATURE_DEFAULT_FOOTSTEP_DISTANCE = 6;
|
||||
|
||||
// Plays a creature's voice/alert sound with consistent positioning
|
||||
// Returns the sound handle for tracking
|
||||
int play_creature_voice(string sound_file, int listener_x, int creature_x, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
|
||||
{
|
||||
int play_creature_voice(string sound_file, int listener_x, int creature_x,
|
||||
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
|
||||
return play_1d_with_volume_step(sound_file, listener_x, creature_x, false, volume_step);
|
||||
}
|
||||
|
||||
// Plays a creature's footstep sound with consistent positioning
|
||||
// Only plays if within max_distance to avoid cluttering the soundscape
|
||||
void play_creature_footstep(int listener_x, int creature_x, int base_end, int grass_end, int max_distance = CREATURE_DEFAULT_FOOTSTEP_DISTANCE, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
|
||||
{
|
||||
void play_creature_footstep(int listener_x, int creature_x, int base_end, int grass_end,
|
||||
int max_distance = CREATURE_DEFAULT_FOOTSTEP_DISTANCE,
|
||||
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
|
||||
int distance = creature_x - listener_x;
|
||||
if (distance < 0) {
|
||||
distance = -distance;
|
||||
@@ -68,19 +69,18 @@ void play_creature_footstep(int listener_x, int creature_x, int base_end, int gr
|
||||
}
|
||||
|
||||
// Plays a creature attack sound (hitting player, hitting barricade, etc.)
|
||||
void play_creature_attack_sound(string sound_file, int listener_x, int creature_x, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
|
||||
{
|
||||
void play_creature_attack_sound(string sound_file, int listener_x, int creature_x,
|
||||
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
|
||||
play_1d_with_volume_step(sound_file, listener_x, creature_x, false, volume_step);
|
||||
}
|
||||
|
||||
// Plays a creature death/fall sound
|
||||
void play_creature_death_sound(string sound_file, int listener_x, int creature_x, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
|
||||
{
|
||||
void play_creature_death_sound(string sound_file, int listener_x, int creature_x,
|
||||
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
|
||||
play_1d_with_volume_step(sound_file, listener_x, creature_x, false, volume_step);
|
||||
}
|
||||
|
||||
string get_creature_death_sound_from_alert(string alert_sound)
|
||||
{
|
||||
string get_creature_death_sound_from_alert(string alert_sound) {
|
||||
if (alert_sound == "") {
|
||||
return "";
|
||||
}
|
||||
@@ -98,7 +98,7 @@ string get_creature_death_sound_from_alert(string alert_sound)
|
||||
|
||||
if (filename == "bandit3" || filename == "bandit4") {
|
||||
string female_death = "sounds/enemies/bandit_female_dies.ogg";
|
||||
if (file_exists(female_death)) {
|
||||
if (audio_asset_exists(female_death)) {
|
||||
return female_death;
|
||||
}
|
||||
}
|
||||
@@ -118,15 +118,15 @@ string get_creature_death_sound_from_alert(string alert_sound)
|
||||
}
|
||||
|
||||
string death_sound = "sounds/enemies/" + filename + "_dies.ogg";
|
||||
if (!file_exists(death_sound)) {
|
||||
if (!audio_asset_exists(death_sound)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return death_sound;
|
||||
}
|
||||
|
||||
void play_creature_death_sounds(string default_sound, string alert_sound, int listener_x, int creature_x, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
|
||||
{
|
||||
void play_creature_death_sounds(string default_sound, string alert_sound, int listener_x, int creature_x,
|
||||
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
|
||||
play_creature_death_sound(default_sound, listener_x, creature_x, volume_step);
|
||||
|
||||
string death_sound = get_creature_death_sound_from_alert(alert_sound);
|
||||
@@ -136,7 +136,7 @@ void play_creature_death_sounds(string default_sound, string alert_sound, int li
|
||||
}
|
||||
|
||||
// Plays a creature hit/damage sound (when player damages the creature)
|
||||
void play_creature_hit_sound(string sound_file, int listener_x, int creature_x, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
|
||||
{
|
||||
void play_creature_hit_sound(string sound_file, int listener_x, int creature_x,
|
||||
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
|
||||
play_1d_with_volume_step(sound_file, listener_x, creature_x, false, volume_step);
|
||||
}
|
||||
|
||||
+77
-45
@@ -3,7 +3,7 @@
|
||||
|
||||
string[] bandit_sounds = {"sounds/enemies/bandit1.ogg", "sounds/enemies/bandit2.ogg"};
|
||||
|
||||
string[] get_invader_sound_list(const string&in invader_type) {
|
||||
string[] get_invader_sound_list(const string& in invader_type) {
|
||||
string[] sounds;
|
||||
if (invader_type == "") {
|
||||
return sounds;
|
||||
@@ -11,7 +11,7 @@ string[] get_invader_sound_list(const string&in invader_type) {
|
||||
|
||||
for (int i = 1; i <= INVADER_SOUND_VARIANTS_MAX; i++) {
|
||||
string sound_file = "sounds/enemies/" + invader_type + i + ".ogg";
|
||||
if (file_exists(sound_file)) {
|
||||
if (audio_asset_exists(sound_file)) {
|
||||
sounds.insert_last(sound_file);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ string[] get_invader_sound_list(const string&in invader_type) {
|
||||
return sounds;
|
||||
}
|
||||
|
||||
string pick_invader_alert_sound(const string&in invader_type) {
|
||||
string pick_invader_alert_sound(const string& in invader_type) {
|
||||
string[] sounds = get_invader_sound_list(invader_type);
|
||||
if (sounds.length() == 0) {
|
||||
sounds = bandit_sounds;
|
||||
@@ -89,12 +89,12 @@ class Bandit {
|
||||
// Initialize wandering behavior (start aggressive during invasion)
|
||||
behavior_state = "aggressive";
|
||||
wander_direction = 0;
|
||||
wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
|
||||
wander_direction_change_interval =
|
||||
random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
|
||||
wander_direction_timer.restart();
|
||||
in_weapon_range = false;
|
||||
}
|
||||
}
|
||||
Bandit@[] bandits;
|
||||
} Bandit @[] bandits;
|
||||
|
||||
void update_bandit_weapon_range_audio() {
|
||||
for (uint i = 0; i < bandits.length(); i++) {
|
||||
@@ -104,12 +104,14 @@ void update_bandit_weapon_range_audio() {
|
||||
bool bandit_range_audio_registered = false;
|
||||
|
||||
void ensure_bandit_range_audio_registration() {
|
||||
if (bandit_range_audio_registered) return;
|
||||
if (bandit_range_audio_registered)
|
||||
return;
|
||||
bandit_range_audio_registered = register_weapon_range_audio_callback(@update_bandit_weapon_range_audio);
|
||||
}
|
||||
|
||||
void clear_bandits() {
|
||||
if (bandits.length() == 0) return;
|
||||
if (bandits.length() == 0)
|
||||
return;
|
||||
|
||||
for (uint i = 0; i < bandits.length(); i++) {
|
||||
force_weapon_range_exit(bandits[i].position, bandits[i].in_weapon_range);
|
||||
@@ -121,7 +123,7 @@ void clear_bandits() {
|
||||
bandits.resize(0);
|
||||
}
|
||||
|
||||
Bandit@ get_bandit_at(int pos) {
|
||||
Bandit @get_bandit_at(int pos) {
|
||||
for (uint i = 0; i < bandits.length(); i++) {
|
||||
if (bandits[i].position == pos) {
|
||||
return @bandits[i];
|
||||
@@ -141,14 +143,18 @@ int pick_bandit_spawn_position(int range_start, int range_end) {
|
||||
|
||||
for (int attempts = 0; attempts < 20; attempts++) {
|
||||
int candidate = random(start, end);
|
||||
if (candidate == x) continue;
|
||||
if (get_bandit_at(candidate) != null) continue;
|
||||
if (candidate == x)
|
||||
continue;
|
||||
if (get_bandit_at(candidate) != null)
|
||||
continue;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
for (int candidate = start; candidate <= end; candidate++) {
|
||||
if (candidate == x) continue;
|
||||
if (get_bandit_at(candidate) != null) continue;
|
||||
if (candidate == x)
|
||||
continue;
|
||||
if (get_bandit_at(candidate) != null)
|
||||
continue;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
@@ -158,7 +164,8 @@ int pick_bandit_spawn_position(int range_start, int range_end) {
|
||||
int pick_bandit_spawn_east_of_player(int min_distance, int max_distance, int range_start, int range_end) {
|
||||
int min_dist = min_distance;
|
||||
int max_dist = max_distance;
|
||||
if (min_dist < 0) min_dist = 0;
|
||||
if (min_dist < 0)
|
||||
min_dist = 0;
|
||||
if (max_dist < min_dist) {
|
||||
int temp = min_dist;
|
||||
min_dist = max_dist;
|
||||
@@ -176,10 +183,13 @@ int pick_bandit_spawn_east_of_player(int min_distance, int max_distance, int ran
|
||||
range_end_norm = temp;
|
||||
}
|
||||
|
||||
if (start < range_start_norm) start = range_start_norm;
|
||||
if (end > range_end_norm) end = range_end_norm;
|
||||
if (start < range_start_norm)
|
||||
start = range_start_norm;
|
||||
if (end > range_end_norm)
|
||||
end = range_end_norm;
|
||||
|
||||
if (start > end) return -1;
|
||||
if (start > end)
|
||||
return -1;
|
||||
|
||||
return pick_bandit_spawn_position(start, end);
|
||||
}
|
||||
@@ -187,7 +197,8 @@ int pick_bandit_spawn_east_of_player(int min_distance, int max_distance, int ran
|
||||
int pick_bandit_spawn_west_of_player(int min_distance, int max_distance, int range_start, int range_end) {
|
||||
int min_dist = min_distance;
|
||||
int max_dist = max_distance;
|
||||
if (min_dist < 0) min_dist = 0;
|
||||
if (min_dist < 0)
|
||||
min_dist = 0;
|
||||
if (max_dist < min_dist) {
|
||||
int temp = min_dist;
|
||||
min_dist = max_dist;
|
||||
@@ -205,29 +216,38 @@ int pick_bandit_spawn_west_of_player(int min_distance, int max_distance, int ran
|
||||
range_end_norm = temp;
|
||||
}
|
||||
|
||||
if (start < range_start_norm) start = range_start_norm;
|
||||
if (end > range_end_norm) end = range_end_norm;
|
||||
if (start < range_start_norm)
|
||||
start = range_start_norm;
|
||||
if (end > range_end_norm)
|
||||
end = range_end_norm;
|
||||
|
||||
if (start > end) return -1;
|
||||
if (start > end)
|
||||
return -1;
|
||||
|
||||
return pick_bandit_spawn_position(start, end);
|
||||
}
|
||||
|
||||
int pick_bandit_spawn_near_player(int range_start, int range_end) {
|
||||
// Preferred: 30-50 tiles east of player.
|
||||
int spawn_x = pick_bandit_spawn_east_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
|
||||
if (spawn_x != -1) return spawn_x;
|
||||
int spawn_x =
|
||||
pick_bandit_spawn_east_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
|
||||
if (spawn_x != -1)
|
||||
return spawn_x;
|
||||
|
||||
// Fallback: 30-50 tiles west when east side is not available.
|
||||
spawn_x = pick_bandit_spawn_west_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
|
||||
if (spawn_x != -1) return spawn_x;
|
||||
spawn_x =
|
||||
pick_bandit_spawn_west_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
|
||||
if (spawn_x != -1)
|
||||
return spawn_x;
|
||||
|
||||
// If map bounds are tight, relax minimum distance but keep around player.
|
||||
spawn_x = pick_bandit_spawn_east_of_player(1, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
|
||||
if (spawn_x != -1) return spawn_x;
|
||||
if (spawn_x != -1)
|
||||
return spawn_x;
|
||||
|
||||
spawn_x = pick_bandit_spawn_west_of_player(1, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
|
||||
if (spawn_x != -1) return spawn_x;
|
||||
if (spawn_x != -1)
|
||||
return spawn_x;
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -250,7 +270,7 @@ int count_bandits_in_range(int range_start, int range_end) {
|
||||
return count;
|
||||
}
|
||||
|
||||
void spawn_bandit(int expansion_start, int expansion_end, const string&in invader_type = "bandit") {
|
||||
void spawn_bandit(int expansion_start, int expansion_end, const string& in invader_type = "bandit") {
|
||||
int spawn_x = -1;
|
||||
if (invasion_active) {
|
||||
spawn_x = pick_bandit_spawn_near_player(expansion_start, expansion_end);
|
||||
@@ -258,7 +278,8 @@ void spawn_bandit(int expansion_start, int expansion_end, const string&in invade
|
||||
if (spawn_x == -1) {
|
||||
spawn_x = pick_bandit_spawn_position(expansion_start, expansion_end);
|
||||
}
|
||||
if (spawn_x == -1) return;
|
||||
if (spawn_x == -1)
|
||||
return;
|
||||
|
||||
int home_start = expansion_start;
|
||||
int home_end = expansion_end;
|
||||
@@ -271,7 +292,7 @@ void spawn_bandit(int expansion_start, int expansion_end, const string&in invade
|
||||
}
|
||||
}
|
||||
|
||||
Bandit@ b = Bandit(spawn_x, home_start, home_end, invader_type);
|
||||
Bandit @b = Bandit(spawn_x, home_start, home_end, invader_type);
|
||||
if (!invasion_active) {
|
||||
b.behavior_state = "wandering";
|
||||
}
|
||||
@@ -285,7 +306,7 @@ void spawn_bandit(int expansion_start, int expansion_end, const string&in invade
|
||||
}
|
||||
}
|
||||
|
||||
bool can_bandit_attack_player(Bandit@ bandit) {
|
||||
bool can_bandit_attack_player(Bandit @bandit) {
|
||||
if (player_health <= 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -302,7 +323,7 @@ bool can_bandit_attack_player(Bandit@ bandit) {
|
||||
return y <= BANDIT_ATTACK_MAX_HEIGHT;
|
||||
}
|
||||
|
||||
bool try_attack_player_bandit(Bandit@ bandit) {
|
||||
bool try_attack_player_bandit(Bandit @bandit) {
|
||||
if (!can_bandit_attack_player(bandit)) {
|
||||
return false;
|
||||
}
|
||||
@@ -336,16 +357,19 @@ bool try_attack_player_bandit(Bandit@ bandit) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void try_attack_barricade_bandit(Bandit@ bandit) {
|
||||
if (barricade_health <= 0) return;
|
||||
if (bandit.attack_timer.elapsed < BANDIT_ATTACK_INTERVAL) return;
|
||||
void try_attack_barricade_bandit(Bandit @bandit) {
|
||||
if (barricade_health <= 0)
|
||||
return;
|
||||
if (bandit.attack_timer.elapsed < BANDIT_ATTACK_INTERVAL)
|
||||
return;
|
||||
|
||||
bandit.attack_timer.restart();
|
||||
|
||||
// Bandits do 1-2 damage to barricade
|
||||
int damage = random(BANDIT_DAMAGE_MIN, BANDIT_DAMAGE_MAX);
|
||||
barricade_health -= damage;
|
||||
if (barricade_health < 0) barricade_health = 0;
|
||||
if (barricade_health < 0)
|
||||
barricade_health = 0;
|
||||
|
||||
// Play weapon swing sound (barricade hits share a common impact sound)
|
||||
if (bandit.weapon_type == "spear") {
|
||||
@@ -372,7 +396,7 @@ void try_attack_barricade_bandit(Bandit@ bandit) {
|
||||
}
|
||||
}
|
||||
|
||||
void update_bandit(Bandit@ bandit, bool audio_active) {
|
||||
void update_bandit(Bandit @bandit, bool audio_active) {
|
||||
bool enforce_home = (!invasion_active && bandit.home_start <= bandit.home_end);
|
||||
if (enforce_home) {
|
||||
if (bandit.position < bandit.home_start) {
|
||||
@@ -395,14 +419,16 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
|
||||
if (bandit.sound_handle != -1) {
|
||||
p.destroy_sound(bandit.sound_handle);
|
||||
}
|
||||
bandit.sound_handle = play_1d_with_volume_step(bandit.alert_sound, x, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
|
||||
bandit.sound_handle =
|
||||
play_1d_with_volume_step(bandit.alert_sound, x, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
if (try_attack_player_bandit(bandit)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bandit.move_timer.elapsed < bandit.move_interval) return;
|
||||
if (bandit.move_timer.elapsed < bandit.move_interval)
|
||||
return;
|
||||
bandit.move_timer.restart();
|
||||
|
||||
// If barricade is up and bandit is at the edge of base, attack barricade
|
||||
@@ -423,7 +449,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
|
||||
if (bandit.wander_direction_timer.elapsed > bandit.wander_direction_change_interval) {
|
||||
// Time to change direction
|
||||
bandit.wander_direction = random(-1, 1);
|
||||
bandit.wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
|
||||
bandit.wander_direction_change_interval =
|
||||
random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
|
||||
bandit.wander_direction_timer.restart();
|
||||
}
|
||||
|
||||
@@ -444,7 +471,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
|
||||
} else {
|
||||
bandit.position = target_x;
|
||||
if (audio_active) {
|
||||
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
|
||||
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END,
|
||||
BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -479,7 +507,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
|
||||
}
|
||||
|
||||
int target_x = bandit.position + direction;
|
||||
if (target_x < 0 || target_x >= MAP_SIZE) return;
|
||||
if (target_x < 0 || target_x >= MAP_SIZE)
|
||||
return;
|
||||
|
||||
if (enforce_home && (target_x < bandit.home_start || target_x > bandit.home_end)) {
|
||||
return;
|
||||
@@ -493,7 +522,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
|
||||
|
||||
bandit.position = target_x;
|
||||
if (audio_active) {
|
||||
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
|
||||
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE,
|
||||
BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -506,7 +536,8 @@ void update_bandits() {
|
||||
bool limit_audio = (areaStarts.length() > 0);
|
||||
|
||||
for (uint i = 0; i < bandits.length(); i++) {
|
||||
bool audio_active = !limit_audio || range_overlaps_active_areas(bandits[i].position, bandits[i].position, areaStarts, areaEnds);
|
||||
bool audio_active =
|
||||
!limit_audio || range_overlaps_active_areas(bandits[i].position, bandits[i].position, areaStarts, areaEnds);
|
||||
update_bandit(bandits[i], audio_active);
|
||||
}
|
||||
}
|
||||
@@ -520,7 +551,8 @@ bool damage_bandit_at(int pos, int damage) {
|
||||
p.destroy_sound(bandits[i].sound_handle);
|
||||
bandits[i].sound_handle = -1;
|
||||
}
|
||||
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", bandits[i].alert_sound, x, pos, BANDIT_SOUND_VOLUME_STEP);
|
||||
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", bandits[i].alert_sound, x, pos,
|
||||
BANDIT_SOUND_VOLUME_STEP);
|
||||
bandits.remove_at(i);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -26,8 +26,7 @@ class FlyingCreatureConfig {
|
||||
int max_count;
|
||||
int sight_range;
|
||||
bool flee_on_sight;
|
||||
}
|
||||
FlyingCreatureConfig@[] flying_creature_configs;
|
||||
} FlyingCreatureConfig @[] flying_creature_configs;
|
||||
|
||||
class FlyingCreature {
|
||||
int position;
|
||||
@@ -48,7 +47,7 @@ class FlyingCreature {
|
||||
timer fade_timer;
|
||||
bool in_weapon_range;
|
||||
|
||||
FlyingCreature(string type, int pos, int home_start, int home_end, FlyingCreatureConfig@ cfg) {
|
||||
FlyingCreature(string type, int pos, int home_start, int home_end, FlyingCreatureConfig @cfg) {
|
||||
position = pos;
|
||||
health = cfg.health;
|
||||
height = random(cfg.min_height, cfg.max_height);
|
||||
@@ -70,8 +69,7 @@ class FlyingCreature {
|
||||
ready_to_remove = false;
|
||||
in_weapon_range = false;
|
||||
}
|
||||
}
|
||||
FlyingCreature@[] flying_creatures;
|
||||
} FlyingCreature @[] flying_creatures;
|
||||
|
||||
void update_flying_creature_weapon_range_audio() {
|
||||
for (uint i = 0; i < flying_creatures.length(); i++) {
|
||||
@@ -87,14 +85,16 @@ void update_flying_creature_weapon_range_audio() {
|
||||
bool flying_creature_range_audio_registered = false;
|
||||
|
||||
void ensure_flying_creature_range_audio_registration() {
|
||||
if (flying_creature_range_audio_registered) return;
|
||||
flying_creature_range_audio_registered = register_weapon_range_audio_callback(@update_flying_creature_weapon_range_audio);
|
||||
if (flying_creature_range_audio_registered)
|
||||
return;
|
||||
flying_creature_range_audio_registered =
|
||||
register_weapon_range_audio_callback(@update_flying_creature_weapon_range_audio);
|
||||
}
|
||||
|
||||
void init_flying_creature_configs() {
|
||||
flying_creature_configs.resize(0);
|
||||
|
||||
FlyingCreatureConfig@ goose_cfg = FlyingCreatureConfig();
|
||||
FlyingCreatureConfig @goose_cfg = FlyingCreatureConfig();
|
||||
goose_cfg.id = "goose";
|
||||
goose_cfg.drop_type = "goose";
|
||||
goose_cfg.spawn_mode = "water";
|
||||
@@ -118,7 +118,7 @@ void init_flying_creature_configs() {
|
||||
goose_cfg.flee_on_sight = false;
|
||||
flying_creature_configs.insert_last(goose_cfg);
|
||||
|
||||
FlyingCreatureConfig@ turkey_cfg = FlyingCreatureConfig();
|
||||
FlyingCreatureConfig @turkey_cfg = FlyingCreatureConfig();
|
||||
turkey_cfg.id = "turkey";
|
||||
turkey_cfg.drop_type = "turkey";
|
||||
turkey_cfg.spawn_mode = "forest";
|
||||
@@ -143,7 +143,7 @@ void init_flying_creature_configs() {
|
||||
flying_creature_configs.insert_last(turkey_cfg);
|
||||
}
|
||||
|
||||
FlyingCreatureConfig@ get_flying_creature_config(string creature_type) {
|
||||
FlyingCreatureConfig @get_flying_creature_config(string creature_type) {
|
||||
for (uint i = 0; i < flying_creature_configs.length(); i++) {
|
||||
if (flying_creature_configs[i].id == creature_type) {
|
||||
return @flying_creature_configs[i];
|
||||
@@ -152,7 +152,7 @@ FlyingCreatureConfig@ get_flying_creature_config(string creature_type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
FlyingCreatureConfig@ get_flying_creature_config_by_drop_type(string drop_type) {
|
||||
FlyingCreatureConfig @get_flying_creature_config_by_drop_type(string drop_type) {
|
||||
for (uint i = 0; i < flying_creature_configs.length(); i++) {
|
||||
if (flying_creature_configs[i].drop_type == drop_type) {
|
||||
return @flying_creature_configs[i];
|
||||
@@ -176,7 +176,7 @@ void clear_flying_creatures() {
|
||||
flying_creatures.resize(0);
|
||||
}
|
||||
|
||||
FlyingCreature@ get_flying_creature_at(int pos) {
|
||||
FlyingCreature @get_flying_creature_at(int pos) {
|
||||
for (uint i = 0; i < flying_creatures.length(); i++) {
|
||||
if (flying_creatures[i].position == pos) {
|
||||
return @flying_creatures[i];
|
||||
@@ -195,9 +195,10 @@ int get_flying_creature_count(string creature_type) {
|
||||
return count;
|
||||
}
|
||||
|
||||
bool get_random_flying_creature_area(FlyingCreatureConfig@ cfg, int &out area_start, int &out area_end) {
|
||||
bool get_random_flying_creature_area(FlyingCreatureConfig @cfg, int& out area_start, int& out area_end) {
|
||||
if (cfg.spawn_mode == "forest") {
|
||||
if (!get_random_forest_area(area_start, area_end)) return false;
|
||||
if (!get_random_forest_area(area_start, area_end))
|
||||
return false;
|
||||
} else {
|
||||
int stream_count = int(world_streams.length());
|
||||
int mountain_stream_count = 0;
|
||||
@@ -206,7 +207,8 @@ bool get_random_flying_creature_area(FlyingCreatureConfig@ cfg, int &out area_st
|
||||
}
|
||||
|
||||
int total_areas = stream_count + mountain_stream_count;
|
||||
if (total_areas <= 0) return false;
|
||||
if (total_areas <= 0)
|
||||
return false;
|
||||
|
||||
int pick = random(0, total_areas - 1);
|
||||
if (pick < stream_count) {
|
||||
@@ -229,15 +231,19 @@ bool get_random_flying_creature_area(FlyingCreatureConfig@ cfg, int &out area_st
|
||||
|
||||
area_start -= cfg.max_dist_from_water;
|
||||
area_end += cfg.max_dist_from_water;
|
||||
if (area_start < 0) area_start = 0;
|
||||
if (area_end >= MAP_SIZE) area_end = MAP_SIZE - 1;
|
||||
if (area_start < 0)
|
||||
area_start = 0;
|
||||
if (area_end >= MAP_SIZE)
|
||||
area_end = MAP_SIZE - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_random_forest_area(int &out area_start, int &out area_end) {
|
||||
if (expanded_area_start == -1) return false;
|
||||
bool get_random_forest_area(int& out area_start, int& out area_end) {
|
||||
if (expanded_area_start == -1)
|
||||
return false;
|
||||
int total = int(expanded_terrain_types.length());
|
||||
if (total <= 0) return false;
|
||||
if (total <= 0)
|
||||
return false;
|
||||
|
||||
int[] segment_starts;
|
||||
int[] segment_ends;
|
||||
@@ -257,7 +263,8 @@ bool get_random_forest_area(int &out area_start, int &out area_end) {
|
||||
if (nextTerrain.find("mountain:") == 0) {
|
||||
nextTerrain = nextTerrain.substr(9);
|
||||
}
|
||||
if (nextTerrain != terrain) break;
|
||||
if (nextTerrain != terrain)
|
||||
break;
|
||||
index++;
|
||||
}
|
||||
int segment_end = index;
|
||||
@@ -268,7 +275,8 @@ bool get_random_forest_area(int &out area_start, int &out area_end) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if (total_tiles <= 0) return false;
|
||||
if (total_tiles <= 0)
|
||||
return false;
|
||||
|
||||
int pick = random(0, total_tiles - 1);
|
||||
for (uint i = 0; i < segment_starts.length(); i++) {
|
||||
@@ -284,8 +292,9 @@ bool get_random_forest_area(int &out area_start, int &out area_end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool find_flying_creature_spawn(FlyingCreatureConfig@ cfg, int &out spawn_x, int &out area_start, int &out area_end) {
|
||||
if (!get_random_flying_creature_area(cfg, area_start, area_end)) return false;
|
||||
bool find_flying_creature_spawn(FlyingCreatureConfig @cfg, int& out spawn_x, int& out area_start, int& out area_end) {
|
||||
if (!get_random_flying_creature_area(cfg, area_start, area_end))
|
||||
return false;
|
||||
|
||||
for (int attempts = 0; attempts < 20; attempts++) {
|
||||
int candidate = random(area_start, area_end);
|
||||
@@ -297,7 +306,7 @@ bool find_flying_creature_spawn(FlyingCreatureConfig@ cfg, int &out spawn_x, int
|
||||
return false;
|
||||
}
|
||||
|
||||
void fly_away_flying_creature(FlyingCreature@ creature, FlyingCreatureConfig@ cfg) {
|
||||
void fly_away_flying_creature(FlyingCreature @creature, FlyingCreatureConfig @cfg) {
|
||||
creature.state = "fading";
|
||||
creature.fading_out = true;
|
||||
creature.ready_to_remove = false;
|
||||
@@ -314,8 +323,9 @@ void fly_away_flying_creature(FlyingCreature@ creature, FlyingCreatureConfig@ cf
|
||||
}
|
||||
|
||||
bool spawn_flying_creature(string creature_type) {
|
||||
FlyingCreatureConfig@ cfg = get_flying_creature_config(creature_type);
|
||||
if (cfg is null) return false;
|
||||
FlyingCreatureConfig @cfg = get_flying_creature_config(creature_type);
|
||||
if (cfg is null)
|
||||
return false;
|
||||
|
||||
int spawn_x = -1;
|
||||
int area_start = 0;
|
||||
@@ -325,7 +335,7 @@ bool spawn_flying_creature(string creature_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
// Play looping sound that follows the flying creature
|
||||
int[] areaStarts;
|
||||
@@ -337,9 +347,10 @@ bool spawn_flying_creature(string creature_type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void update_flying_creature(FlyingCreature@ creature, bool audio_active) {
|
||||
FlyingCreatureConfig@ cfg = get_flying_creature_config(creature.creature_type);
|
||||
if (cfg is null) return;
|
||||
void update_flying_creature(FlyingCreature @creature, bool audio_active) {
|
||||
FlyingCreatureConfig @cfg = get_flying_creature_config(creature.creature_type);
|
||||
if (cfg is null)
|
||||
return;
|
||||
|
||||
if (creature.state == "fading") {
|
||||
if (!creature.fading_out) {
|
||||
@@ -353,8 +364,10 @@ void update_flying_creature(FlyingCreature@ creature, bool audio_active) {
|
||||
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);
|
||||
if (progress < 0.0) progress = 0.0;
|
||||
if (progress > 1.0) progress = 1.0;
|
||||
if (progress < 0.0)
|
||||
progress = 0.0;
|
||||
if (progress > 1.0)
|
||||
progress = 1.0;
|
||||
float volume = 0.0 + (FLYING_CREATURE_FADE_OUT_MIN_VOLUME * progress);
|
||||
p.update_sound_start_values(creature.sound_handle, 0.0, volume, 1.0);
|
||||
}
|
||||
@@ -388,7 +401,8 @@ void update_flying_creature(FlyingCreature@ creature, bool audio_active) {
|
||||
if (creature.sound_handle != -1) {
|
||||
p.destroy_sound(creature.sound_handle);
|
||||
}
|
||||
creature.sound_handle = play_1d_with_volume_step(creature.voice_sound, x, creature.position, true, cfg.sound_volume_step);
|
||||
creature.sound_handle =
|
||||
play_1d_with_volume_step(creature.voice_sound, x, creature.position, true, cfg.sound_volume_step);
|
||||
}
|
||||
|
||||
if (cfg.fly_away_chance > 0 && random(1, 1000) <= cfg.fly_away_chance) {
|
||||
@@ -404,11 +418,14 @@ void update_flying_creature(FlyingCreature@ creature, bool audio_active) {
|
||||
if (cfg.flee_on_sight && cfg.sight_range > 0) {
|
||||
int distance_to_player = abs(x - creature.position);
|
||||
if (distance_to_player <= cfg.sight_range) {
|
||||
if (x > creature.position) dir = -1;
|
||||
else if (x < creature.position) dir = 1;
|
||||
if (x > creature.position)
|
||||
dir = -1;
|
||||
else if (x < creature.position)
|
||||
dir = 1;
|
||||
}
|
||||
}
|
||||
if (dir == 0) dir = random(-1, 1);
|
||||
if (dir == 0)
|
||||
dir = random(-1, 1);
|
||||
if (dir != 0) {
|
||||
int target_x = creature.position + dir;
|
||||
if (target_x < creature.area_start || target_x > creature.area_end) {
|
||||
@@ -434,11 +451,14 @@ void update_flying_creature(FlyingCreature@ creature, bool audio_active) {
|
||||
}
|
||||
|
||||
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 > 100.0) pitch_percent = 100.0;
|
||||
if (pitch_percent < 50.0)
|
||||
pitch_percent = 50.0;
|
||||
if (pitch_percent > 100.0)
|
||||
pitch_percent = 100.0;
|
||||
|
||||
if (audio_active) {
|
||||
creature.fall_sound_handle = p.play_extended_1d(cfg.fall_sound, x, creature.position, 0, 0, true, 0, 0.0, 0.0, pitch_percent);
|
||||
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 (creature.fall_sound_handle != -1) {
|
||||
p.update_sound_positioning_values(creature.fall_sound_handle, -1.0, cfg.sound_volume_step, true);
|
||||
}
|
||||
@@ -466,7 +486,9 @@ void update_flying_creatures() {
|
||||
bool limit_audio = (areaStarts.length() > 0);
|
||||
|
||||
for (uint i = 0; i < flying_creatures.length(); i++) {
|
||||
bool audio_active = !limit_audio || range_overlaps_active_areas(flying_creatures[i].position, flying_creatures[i].position, areaStarts, areaEnds);
|
||||
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) {
|
||||
@@ -486,8 +508,9 @@ void update_flying_creatures() {
|
||||
|
||||
void attempt_hourly_flying_creature_spawn() {
|
||||
for (uint i = 0; i < flying_creature_configs.length(); i++) {
|
||||
FlyingCreatureConfig@ cfg = flying_creature_configs[i];
|
||||
if (get_flying_creature_count(cfg.id) >= cfg.max_count) continue;
|
||||
FlyingCreatureConfig @cfg = flying_creature_configs[i];
|
||||
if (get_flying_creature_count(cfg.id) >= cfg.max_count)
|
||||
continue;
|
||||
if (random(1, 100) <= cfg.hourly_spawn_chance) {
|
||||
spawn_flying_creature(cfg.id);
|
||||
}
|
||||
@@ -497,8 +520,9 @@ void attempt_hourly_flying_creature_spawn() {
|
||||
bool damage_flying_creature_at(int pos, int damage) {
|
||||
for (uint i = 0; i < flying_creatures.length(); i++) {
|
||||
if (flying_creatures[i].position == pos && flying_creatures[i].state == "flying") {
|
||||
FlyingCreatureConfig@ cfg = get_flying_creature_config(flying_creatures[i].creature_type);
|
||||
if (cfg is null) return false;
|
||||
FlyingCreatureConfig @cfg = get_flying_creature_config(flying_creatures[i].creature_type);
|
||||
if (cfg is null)
|
||||
return false;
|
||||
|
||||
flying_creatures[i].health -= damage;
|
||||
if (flying_creatures[i].health <= 0) {
|
||||
@@ -511,9 +535,11 @@ bool damage_flying_creature_at(int pos, int damage) {
|
||||
}
|
||||
|
||||
float pitch_percent = 50.0 + (50.0 * (float(flying_creatures[i].height) / float(cfg.max_height)));
|
||||
flying_creatures[i].fall_sound_handle = p.play_extended_1d(cfg.fall_sound, x, pos, 0, 0, true, 0, 0.0, 0.0, pitch_percent);
|
||||
flying_creatures[i].fall_sound_handle =
|
||||
p.play_extended_1d(cfg.fall_sound, x, pos, 0, 0, true, 0, 0.0, 0.0, pitch_percent);
|
||||
if (flying_creatures[i].fall_sound_handle != -1) {
|
||||
p.update_sound_positioning_values(flying_creatures[i].fall_sound_handle, -1.0, cfg.sound_volume_step, true);
|
||||
p.update_sound_positioning_values(flying_creatures[i].fall_sound_handle, -1.0,
|
||||
cfg.sound_volume_step, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -36,8 +36,7 @@ class GroundGame {
|
||||
next_move_delay = random(BOAR_MOVE_INTERVAL_MIN, BOAR_MOVE_INTERVAL_MAX);
|
||||
in_weapon_range = false;
|
||||
}
|
||||
}
|
||||
GroundGame@[] ground_games;
|
||||
} GroundGame @[] ground_games;
|
||||
|
||||
void update_ground_game_weapon_range_audio() {
|
||||
for (uint i = 0; i < ground_games.length(); i++) {
|
||||
@@ -47,12 +46,14 @@ void update_ground_game_weapon_range_audio() {
|
||||
bool ground_game_range_audio_registered = false;
|
||||
|
||||
void ensure_ground_game_range_audio_registration() {
|
||||
if (ground_game_range_audio_registered) return;
|
||||
if (ground_game_range_audio_registered)
|
||||
return;
|
||||
ground_game_range_audio_registered = register_weapon_range_audio_callback(@update_ground_game_weapon_range_audio);
|
||||
}
|
||||
|
||||
void clear_ground_games() {
|
||||
if (ground_games.length() == 0) return;
|
||||
if (ground_games.length() == 0)
|
||||
return;
|
||||
|
||||
for (uint i = 0; i < ground_games.length(); i++) {
|
||||
force_weapon_range_exit(ground_games[i].position, ground_games[i].in_weapon_range);
|
||||
@@ -64,7 +65,7 @@ void clear_ground_games() {
|
||||
ground_games.resize(0);
|
||||
}
|
||||
|
||||
GroundGame@ get_ground_game_at(int pos) {
|
||||
GroundGame @get_ground_game_at(int pos) {
|
||||
for (uint i = 0; i < ground_games.length(); i++) {
|
||||
if (ground_games[i].position == pos) {
|
||||
return @ground_games[i];
|
||||
@@ -80,16 +81,18 @@ void spawn_ground_game(int expansion_start, int expansion_end) {
|
||||
int candidate = random(expansion_start, expansion_end);
|
||||
|
||||
// Don't spawn too close to base (keep away from BASE_END)
|
||||
if (candidate <= BASE_END + 5) continue;
|
||||
if (candidate <= BASE_END + 5)
|
||||
continue;
|
||||
|
||||
if (get_ground_game_at(candidate) == null) {
|
||||
spawn_x = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (spawn_x == -1) return; // Failed to find spot
|
||||
if (spawn_x == -1)
|
||||
return; // Failed to find spot
|
||||
|
||||
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);
|
||||
// Play looping sound that follows the boar
|
||||
int[] areaStarts;
|
||||
@@ -100,34 +103,40 @@ void spawn_ground_game(int expansion_start, int expansion_end) {
|
||||
}
|
||||
}
|
||||
|
||||
bool can_ground_game_attack_player(GroundGame@ game) {
|
||||
if (player_health <= 0) return false;
|
||||
bool can_ground_game_attack_player(GroundGame @game) {
|
||||
if (player_health <= 0)
|
||||
return false;
|
||||
|
||||
// Check if player is on ground (ground game can't fly/climb)
|
||||
if (y > 0) return false;
|
||||
if (y > 0)
|
||||
return false;
|
||||
|
||||
if (abs(game.position - x) > 1) return false;
|
||||
if (abs(game.position - x) > 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_attack_player_ground_game(GroundGame@ game) {
|
||||
if (!can_ground_game_attack_player(game)) return false;
|
||||
bool try_attack_player_ground_game(GroundGame @game) {
|
||||
if (!can_ground_game_attack_player(game))
|
||||
return false;
|
||||
|
||||
if (game.attack_timer.elapsed < BOAR_ATTACK_INTERVAL) return false;
|
||||
if (game.attack_timer.elapsed < BOAR_ATTACK_INTERVAL)
|
||||
return false;
|
||||
|
||||
game.attack_timer.restart();
|
||||
|
||||
// Attack!
|
||||
int damage = random(BOAR_DAMAGE_MIN, BOAR_DAMAGE_MAX);
|
||||
player_health -= damage;
|
||||
if (player_health < 0) player_health = 0;
|
||||
if (player_health < 0)
|
||||
player_health = 0;
|
||||
play_player_damage_sound();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void update_ground_game(GroundGame@ game, bool audio_active) {
|
||||
void update_ground_game(GroundGame @game, bool audio_active) {
|
||||
// Update looping sound position
|
||||
if (!audio_active) {
|
||||
if (game.sound_handle != -1) {
|
||||
@@ -152,7 +161,8 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
|
||||
// Movement logic
|
||||
int move_speed = (game.state == "charging") ? BOAR_CHARGE_SPEED : game.next_move_delay;
|
||||
|
||||
if (game.move_timer.elapsed < move_speed) return;
|
||||
if (game.move_timer.elapsed < move_speed)
|
||||
return;
|
||||
game.move_timer.restart();
|
||||
if (game.state == "wandering") {
|
||||
game.next_move_delay = random(BOAR_MOVE_INTERVAL_MIN, BOAR_MOVE_INTERVAL_MAX);
|
||||
@@ -177,7 +187,8 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
|
||||
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
|
||||
game.position = target;
|
||||
if (audio_active) {
|
||||
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
|
||||
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE,
|
||||
BOAR_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -192,7 +203,8 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
|
||||
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
|
||||
game.position = target;
|
||||
if (audio_active) {
|
||||
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
|
||||
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE,
|
||||
BOAR_SOUND_VOLUME_STEP);
|
||||
}
|
||||
} else {
|
||||
game.wander_direction = -game.wander_direction; // Turn around
|
||||
@@ -209,14 +221,17 @@ void update_ground_games() {
|
||||
bool limit_audio = (areaStarts.length() > 0);
|
||||
|
||||
for (uint i = 0; i < ground_games.length(); i++) {
|
||||
bool audio_active = !limit_audio || range_overlaps_active_areas(ground_games[i].position, ground_games[i].position, areaStarts, areaEnds);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void attempt_hourly_ground_game_spawn() {
|
||||
if (expanded_area_start == -1) return;
|
||||
if (ground_games.length() >= BOAR_MAX_COUNT) return;
|
||||
if (expanded_area_start == -1)
|
||||
return;
|
||||
if (ground_games.length() >= BOAR_MAX_COUNT)
|
||||
return;
|
||||
|
||||
if (random(1, 100) <= BOAR_SPAWN_CHANCE_PER_HOUR) {
|
||||
spawn_ground_game(expanded_area_start, expanded_area_end);
|
||||
@@ -246,10 +261,22 @@ bool damage_ground_game_at(int pos, int damage) {
|
||||
}
|
||||
|
||||
// Backward compatibility aliases (to be removed after refactoring)
|
||||
GroundGame@[]@ boars = @ground_games;
|
||||
GroundGame@ get_boar_at(int pos) { return get_ground_game_at(pos); }
|
||||
void clear_boars() { clear_ground_games(); }
|
||||
void spawn_boar(int expansion_start, int expansion_end) { spawn_ground_game(expansion_start, expansion_end); }
|
||||
void update_boars() { update_ground_games(); }
|
||||
void attempt_hourly_boar_spawn() { attempt_hourly_ground_game_spawn(); }
|
||||
bool damage_boar_at(int pos, int damage) { return damage_ground_game_at(pos, damage); }
|
||||
GroundGame @[] @boars = @ground_games;
|
||||
GroundGame @get_boar_at(int pos) {
|
||||
return get_ground_game_at(pos);
|
||||
}
|
||||
void clear_boars() {
|
||||
clear_ground_games();
|
||||
}
|
||||
void spawn_boar(int expansion_start, int expansion_end) {
|
||||
spawn_ground_game(expansion_start, expansion_end);
|
||||
}
|
||||
void update_boars() {
|
||||
update_ground_games();
|
||||
}
|
||||
void attempt_hourly_boar_spawn() {
|
||||
attempt_hourly_ground_game_spawn();
|
||||
}
|
||||
bool damage_boar_at(int pos, int damage) {
|
||||
return damage_ground_game_at(pos, damage);
|
||||
}
|
||||
|
||||
+131
-77
@@ -3,12 +3,8 @@
|
||||
|
||||
string[] undead_zombie_sounds = {"sounds/enemies/zombie1.ogg"};
|
||||
string[] undead_wight_sounds = {"sounds/enemies/wight1.ogg"};
|
||||
string[] undead_vampyr_sounds = {
|
||||
"sounds/enemies/vampyr1.ogg",
|
||||
"sounds/enemies/vampyr2.ogg",
|
||||
"sounds/enemies/vampyr3.ogg",
|
||||
"sounds/enemies/vampyr4.ogg"
|
||||
};
|
||||
string[] undead_vampyr_sounds = {"sounds/enemies/vampyr1.ogg", "sounds/enemies/vampyr2.ogg",
|
||||
"sounds/enemies/vampyr3.ogg", "sounds/enemies/vampyr4.ogg"};
|
||||
string[] undead_resident_sounds = {"sounds/enemies/undead_resident1.ogg"};
|
||||
|
||||
int wight_spawn_chance = WIGHT_SPAWN_CHANCE_START;
|
||||
@@ -16,28 +12,37 @@ int wight_spawned_this_night_count = 0;
|
||||
int vampyr_spawn_chance = VAMPYR_SPAWN_CHANCE_START;
|
||||
int vampyr_spawned_this_night_count = 0;
|
||||
|
||||
int get_undead_base_health(const string &in undead_type) {
|
||||
if (undead_type == "wight") return WIGHT_HEALTH;
|
||||
if (undead_type == "vampyr") return VAMPYR_HEALTH;
|
||||
if (undead_type == "undead_resident") return UNDEAD_RESIDENT_HEALTH;
|
||||
int get_undead_base_health(const string& in undead_type) {
|
||||
if (undead_type == "wight")
|
||||
return WIGHT_HEALTH;
|
||||
if (undead_type == "vampyr")
|
||||
return VAMPYR_HEALTH;
|
||||
if (undead_type == "undead_resident")
|
||||
return UNDEAD_RESIDENT_HEALTH;
|
||||
return ZOMBIE_HEALTH;
|
||||
}
|
||||
|
||||
int get_undead_damage_min(const string &in undead_type) {
|
||||
if (undead_type == "wight") return WIGHT_DAMAGE_MIN;
|
||||
if (undead_type == "vampyr") return WIGHT_DAMAGE_MIN;
|
||||
if (undead_type == "undead_resident") return UNDEAD_RESIDENT_DAMAGE_MIN;
|
||||
int get_undead_damage_min(const string& in undead_type) {
|
||||
if (undead_type == "wight")
|
||||
return WIGHT_DAMAGE_MIN;
|
||||
if (undead_type == "vampyr")
|
||||
return WIGHT_DAMAGE_MIN;
|
||||
if (undead_type == "undead_resident")
|
||||
return UNDEAD_RESIDENT_DAMAGE_MIN;
|
||||
return ZOMBIE_DAMAGE_MIN;
|
||||
}
|
||||
|
||||
int get_undead_damage_max(const string &in undead_type) {
|
||||
if (undead_type == "wight") return WIGHT_DAMAGE_MAX;
|
||||
if (undead_type == "vampyr") return WIGHT_DAMAGE_MAX;
|
||||
if (undead_type == "undead_resident") return UNDEAD_RESIDENT_DAMAGE_MAX;
|
||||
int get_undead_damage_max(const string& in undead_type) {
|
||||
if (undead_type == "wight")
|
||||
return WIGHT_DAMAGE_MAX;
|
||||
if (undead_type == "vampyr")
|
||||
return WIGHT_DAMAGE_MAX;
|
||||
if (undead_type == "undead_resident")
|
||||
return UNDEAD_RESIDENT_DAMAGE_MAX;
|
||||
return ZOMBIE_DAMAGE_MAX;
|
||||
}
|
||||
|
||||
string pick_undead_voice_sound(const string &in undead_type) {
|
||||
string pick_undead_voice_sound(const string& in undead_type) {
|
||||
if (undead_type == "wight") {
|
||||
int sound_index = random(0, undead_wight_sounds.length() - 1);
|
||||
return undead_wight_sounds[sound_index];
|
||||
@@ -54,10 +59,13 @@ string pick_undead_voice_sound(const string &in undead_type) {
|
||||
return undead_zombie_sounds[sound_index];
|
||||
}
|
||||
|
||||
string get_undead_label(const string &in undead_type) {
|
||||
if (undead_type == "wight") return "wight";
|
||||
if (undead_type == "vampyr") return "vampyr";
|
||||
if (undead_type == "undead_resident") return "undead resident";
|
||||
string get_undead_label(const string& in undead_type) {
|
||||
if (undead_type == "wight")
|
||||
return "wight";
|
||||
if (undead_type == "vampyr")
|
||||
return "vampyr";
|
||||
if (undead_type == "undead_resident")
|
||||
return "undead resident";
|
||||
return "zombie";
|
||||
}
|
||||
|
||||
@@ -87,8 +95,7 @@ class Undead {
|
||||
move_timer.restart();
|
||||
attack_timer.restart();
|
||||
}
|
||||
}
|
||||
Undead@[] undeads;
|
||||
} Undead @[] undeads;
|
||||
|
||||
int count_wights() {
|
||||
int count = 0;
|
||||
@@ -119,7 +126,8 @@ bool has_vampyr() {
|
||||
}
|
||||
|
||||
int get_night_special_undead_spawn_limit(int day) {
|
||||
if (day < 1) day = 1;
|
||||
if (day < 1)
|
||||
day = 1;
|
||||
return 1 + (day / SPECIAL_UNDEAD_SPAWN_DAYS_PER_EXTRA);
|
||||
}
|
||||
|
||||
@@ -131,12 +139,14 @@ void update_undead_weapon_range_audio() {
|
||||
bool undead_range_audio_registered = false;
|
||||
|
||||
void ensure_undead_range_audio_registration() {
|
||||
if (undead_range_audio_registered) return;
|
||||
if (undead_range_audio_registered)
|
||||
return;
|
||||
undead_range_audio_registered = register_weapon_range_audio_callback(@update_undead_weapon_range_audio);
|
||||
}
|
||||
|
||||
void clear_undeads() {
|
||||
if (undeads.length() == 0) return;
|
||||
if (undeads.length() == 0)
|
||||
return;
|
||||
|
||||
for (uint i = 0; i < undeads.length(); i++) {
|
||||
force_weapon_range_exit(undeads[i].position, undeads[i].in_weapon_range);
|
||||
@@ -148,7 +158,7 @@ void clear_undeads() {
|
||||
undeads.resize(0);
|
||||
}
|
||||
|
||||
Undead@ get_undead_at(int pos) {
|
||||
Undead @get_undead_at(int pos) {
|
||||
for (uint i = 0; i < undeads.length(); i++) {
|
||||
if (undeads[i].position == pos) {
|
||||
return @undeads[i];
|
||||
@@ -168,14 +178,18 @@ int pick_undead_spawn_position(int range_start, int range_end) {
|
||||
|
||||
for (int attempts = 0; attempts < 20; attempts++) {
|
||||
int candidate = random(start, end);
|
||||
if (candidate == x) continue;
|
||||
if (get_undead_at(candidate) != null) continue;
|
||||
if (candidate == x)
|
||||
continue;
|
||||
if (get_undead_at(candidate) != null)
|
||||
continue;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
for (int candidate = start; candidate <= end; candidate++) {
|
||||
if (candidate == x) continue;
|
||||
if (get_undead_at(candidate) != null) continue;
|
||||
if (candidate == x)
|
||||
continue;
|
||||
if (get_undead_at(candidate) != null)
|
||||
continue;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
@@ -185,7 +199,8 @@ int pick_undead_spawn_position(int range_start, int range_end) {
|
||||
int pick_undead_spawn_near_player(int min_distance, int max_distance) {
|
||||
int min_dist = min_distance;
|
||||
int max_dist = max_distance;
|
||||
if (min_dist < 0) min_dist = 0;
|
||||
if (min_dist < 0)
|
||||
min_dist = 0;
|
||||
if (max_dist < min_dist) {
|
||||
int temp = min_dist;
|
||||
min_dist = max_dist;
|
||||
@@ -196,9 +211,12 @@ int pick_undead_spawn_near_player(int min_distance, int max_distance) {
|
||||
int distance = random(min_dist, max_dist);
|
||||
int direction = (random(0, 1) == 0) ? -1 : 1;
|
||||
int candidate = x + (distance * direction);
|
||||
if (candidate <= BASE_END || candidate < 0 || candidate >= MAP_SIZE) continue;
|
||||
if (candidate == x) continue;
|
||||
if (get_undead_at(candidate) != null) continue;
|
||||
if (candidate <= BASE_END || candidate < 0 || candidate >= MAP_SIZE)
|
||||
continue;
|
||||
if (candidate == x)
|
||||
continue;
|
||||
if (get_undead_at(candidate) != null)
|
||||
continue;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
@@ -207,22 +225,30 @@ int pick_undead_spawn_near_player(int min_distance, int max_distance) {
|
||||
int right_start = x + min_dist;
|
||||
int right_end = x + max_dist;
|
||||
|
||||
if (left_start < BASE_END + 1) left_start = BASE_END + 1;
|
||||
if (left_end < BASE_END + 1) left_end = BASE_END;
|
||||
if (right_start < BASE_END + 1) right_start = BASE_END + 1;
|
||||
if (left_start < BASE_END + 1)
|
||||
left_start = BASE_END + 1;
|
||||
if (left_end < BASE_END + 1)
|
||||
left_end = BASE_END;
|
||||
if (right_start < BASE_END + 1)
|
||||
right_start = BASE_END + 1;
|
||||
|
||||
if (left_end >= MAP_SIZE) left_end = MAP_SIZE - 1;
|
||||
if (right_start >= MAP_SIZE) right_start = MAP_SIZE;
|
||||
if (right_end >= MAP_SIZE) right_end = MAP_SIZE - 1;
|
||||
if (left_end >= MAP_SIZE)
|
||||
left_end = MAP_SIZE - 1;
|
||||
if (right_start >= MAP_SIZE)
|
||||
right_start = MAP_SIZE;
|
||||
if (right_end >= MAP_SIZE)
|
||||
right_end = MAP_SIZE - 1;
|
||||
|
||||
int candidate = -1;
|
||||
if (random(0, 1) == 0) {
|
||||
if (left_start <= left_end) candidate = pick_undead_spawn_position(left_start, left_end);
|
||||
if (left_start <= left_end)
|
||||
candidate = pick_undead_spawn_position(left_start, left_end);
|
||||
if (candidate == -1 && right_start <= right_end) {
|
||||
candidate = pick_undead_spawn_position(right_start, right_end);
|
||||
}
|
||||
} else {
|
||||
if (right_start <= right_end) candidate = pick_undead_spawn_position(right_start, right_end);
|
||||
if (right_start <= right_end)
|
||||
candidate = pick_undead_spawn_position(right_start, right_end);
|
||||
if (candidate == -1 && left_start <= left_end) {
|
||||
candidate = pick_undead_spawn_position(left_start, left_end);
|
||||
}
|
||||
@@ -231,7 +257,7 @@ int pick_undead_spawn_near_player(int min_distance, int max_distance) {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
void spawn_undead(const string &in undead_type = "zombie") {
|
||||
void spawn_undead(const string& in undead_type = "zombie") {
|
||||
int spawn_x = -1;
|
||||
if (undead_type == "zombie" || undead_type == "undead_resident") {
|
||||
spawn_x = pick_undead_spawn_near_player(ZOMBIE_SPAWN_MIN_DISTANCE, ZOMBIE_SPAWN_MAX_DISTANCE);
|
||||
@@ -239,9 +265,10 @@ void spawn_undead(const string &in undead_type = "zombie") {
|
||||
if (spawn_x == -1) {
|
||||
spawn_x = pick_undead_spawn_position(BASE_END + 1, MAP_SIZE - 1);
|
||||
}
|
||||
if (spawn_x == -1) return;
|
||||
if (spawn_x == -1)
|
||||
return;
|
||||
|
||||
Undead@ undead = Undead(spawn_x, undead_type);
|
||||
Undead @undead = Undead(spawn_x, undead_type);
|
||||
undeads.insert_last(undead);
|
||||
// Play looping sound that follows the undead
|
||||
int[] areaStarts;
|
||||
@@ -252,18 +279,22 @@ void spawn_undead(const string &in undead_type = "zombie") {
|
||||
if (undead_type == "vampyr") {
|
||||
undead.voice_sound = pick_undead_voice_sound(undead_type);
|
||||
}
|
||||
undead.sound_handle = play_1d_with_volume_step(undead.voice_sound, x, spawn_x, loop_voice, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
undead.sound_handle =
|
||||
play_1d_with_volume_step(undead.voice_sound, x, spawn_x, loop_voice, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
void try_attack_barricade_undead(Undead@ undead) {
|
||||
if (barricade_health <= 0) return;
|
||||
if (undead.attack_timer.elapsed < ZOMBIE_ATTACK_INTERVAL) return;
|
||||
void try_attack_barricade_undead(Undead @undead) {
|
||||
if (barricade_health <= 0)
|
||||
return;
|
||||
if (undead.attack_timer.elapsed < ZOMBIE_ATTACK_INTERVAL)
|
||||
return;
|
||||
|
||||
undead.attack_timer.restart();
|
||||
int damage = random(get_undead_damage_min(undead.undead_type), get_undead_damage_max(undead.undead_type));
|
||||
barricade_health -= damage;
|
||||
if (barricade_health < 0) barricade_health = 0;
|
||||
if (barricade_health < 0)
|
||||
barricade_health = 0;
|
||||
|
||||
play_creature_attack_sound("sounds/weapons/axe_hit.ogg", x, undead.position, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
|
||||
@@ -284,7 +315,7 @@ void try_attack_barricade_undead(Undead@ undead) {
|
||||
}
|
||||
}
|
||||
|
||||
bool can_undead_attack_player(Undead@ undead) {
|
||||
bool can_undead_attack_player(Undead @undead) {
|
||||
if (player_health <= 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -308,7 +339,7 @@ bool can_undead_attack_player(Undead@ undead) {
|
||||
return y <= ZOMBIE_ATTACK_MAX_HEIGHT;
|
||||
}
|
||||
|
||||
bool try_attack_player_undead(Undead@ undead) {
|
||||
bool try_attack_player_undead(Undead @undead) {
|
||||
if (!can_undead_attack_player(undead)) {
|
||||
return false;
|
||||
}
|
||||
@@ -327,7 +358,7 @@ bool try_attack_player_undead(Undead@ undead) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void start_vampyr_retreat(Undead@ undead) {
|
||||
void start_vampyr_retreat(Undead @undead) {
|
||||
undead.retreating = true;
|
||||
undead.suppress_voice = true;
|
||||
if (undead.sound_handle != -1) {
|
||||
@@ -337,7 +368,7 @@ void start_vampyr_retreat(Undead@ undead) {
|
||||
undead.move_timer.restart();
|
||||
}
|
||||
|
||||
void try_capture_resident_vampyr(Undead@ undead) {
|
||||
void try_capture_resident_vampyr(Undead @undead) {
|
||||
if (undead.attack_timer.elapsed < VAMPYR_CAPTURE_INTERVAL) {
|
||||
return;
|
||||
}
|
||||
@@ -350,14 +381,15 @@ void try_capture_resident_vampyr(Undead@ undead) {
|
||||
|
||||
if (random(1, 100) <= VAMPYR_CAPTURE_CHANCE) {
|
||||
residents_count--;
|
||||
if (residents_count < 0) residents_count = 0;
|
||||
if (residents_count < 0)
|
||||
residents_count = 0;
|
||||
undead_residents_pending++;
|
||||
speak_with_history("A resident has been taken.", true);
|
||||
start_vampyr_retreat(undead);
|
||||
}
|
||||
}
|
||||
|
||||
void update_undead(Undead@ undead, bool audio_active) {
|
||||
void update_undead(Undead @undead, bool audio_active) {
|
||||
bool is_vampyr = (undead.undead_type == "vampyr");
|
||||
bool loop_voice = !is_vampyr;
|
||||
|
||||
@@ -377,19 +409,22 @@ void update_undead(Undead@ undead, bool audio_active) {
|
||||
if (is_vampyr) {
|
||||
undead.voice_sound = pick_undead_voice_sound(undead.undead_type);
|
||||
}
|
||||
undead.sound_handle = play_1d_with_volume_step(undead.voice_sound, x, undead.position, loop_voice, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
undead.sound_handle =
|
||||
play_1d_with_volume_step(undead.voice_sound, x, undead.position, loop_voice, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
if (try_attack_player_undead(undead)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (undead.undead_type == "vampyr" && !undead.retreating && barricade_health > 0 && undead.position == BASE_END + 1) {
|
||||
if (undead.undead_type == "vampyr" && !undead.retreating && barricade_health > 0 &&
|
||||
undead.position == BASE_END + 1) {
|
||||
try_capture_resident_vampyr(undead);
|
||||
return;
|
||||
}
|
||||
|
||||
if (undead.move_timer.elapsed < ZOMBIE_MOVE_INTERVAL) return;
|
||||
if (undead.move_timer.elapsed < ZOMBIE_MOVE_INTERVAL)
|
||||
return;
|
||||
undead.move_timer.restart();
|
||||
|
||||
if (undead.undead_type != "vampyr" && barricade_health > 0 && undead.position == BASE_END + 1) {
|
||||
@@ -433,12 +468,14 @@ void update_undead(Undead@ undead, bool audio_active) {
|
||||
}
|
||||
} else {
|
||||
direction = random(-1, 1);
|
||||
if (direction == 0) return;
|
||||
if (direction == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int target_x = undead.position + direction;
|
||||
if (target_x < 0 || target_x >= MAP_SIZE) return;
|
||||
if (target_x < 0 || target_x >= MAP_SIZE)
|
||||
return;
|
||||
|
||||
if (undead.undead_type != "vampyr" && target_x <= BASE_END && barricade_health > 0) {
|
||||
try_attack_barricade_undead(undead);
|
||||
@@ -447,7 +484,8 @@ void update_undead(Undead@ undead, bool audio_active) {
|
||||
|
||||
undead.position = target_x;
|
||||
if (audio_active) {
|
||||
play_creature_footstep(x, undead.position, BASE_END, GRASS_END, ZOMBIE_FOOTSTEP_MAX_DISTANCE, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
play_creature_footstep(x, undead.position, BASE_END, GRASS_END, ZOMBIE_FOOTSTEP_MAX_DISTANCE,
|
||||
ZOMBIE_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,7 +516,8 @@ void update_undeads() {
|
||||
if (zombie_swarm_active) {
|
||||
maxCount += ZOMBIE_SWARM_ZOMBIE_MAX_BONUS;
|
||||
}
|
||||
if (maxCount > ZOMBIE_MAX_COUNT_CAP) maxCount = ZOMBIE_MAX_COUNT_CAP;
|
||||
if (maxCount > ZOMBIE_MAX_COUNT_CAP)
|
||||
maxCount = ZOMBIE_MAX_COUNT_CAP;
|
||||
|
||||
int zombie_count = 0;
|
||||
int undead_resident_count = 0;
|
||||
@@ -508,7 +547,8 @@ void update_undeads() {
|
||||
bool limit_audio = (areaStarts.length() > 0);
|
||||
|
||||
for (uint i = 0; i < undeads.length(); i++) {
|
||||
bool audio_active = !limit_audio || range_overlaps_active_areas(undeads[i].position, undeads[i].position, areaStarts, areaEnds);
|
||||
bool audio_active =
|
||||
!limit_audio || range_overlaps_active_areas(undeads[i].position, undeads[i].position, areaStarts, areaEnds);
|
||||
update_undead(undeads[i], audio_active);
|
||||
}
|
||||
|
||||
@@ -555,7 +595,8 @@ void attempt_hourly_wight_spawn() {
|
||||
}
|
||||
|
||||
wight_spawn_chance += WIGHT_SPAWN_CHANCE_STEP;
|
||||
if (wight_spawn_chance > 100) wight_spawn_chance = 100;
|
||||
if (wight_spawn_chance > 100)
|
||||
wight_spawn_chance = 100;
|
||||
}
|
||||
|
||||
void attempt_hourly_vampyr_spawn() {
|
||||
@@ -594,7 +635,8 @@ void attempt_hourly_vampyr_spawn() {
|
||||
}
|
||||
|
||||
vampyr_spawn_chance += VAMPYR_SPAWN_CHANCE_STEP;
|
||||
if (vampyr_spawn_chance > 100) vampyr_spawn_chance = 100;
|
||||
if (vampyr_spawn_chance > 100)
|
||||
vampyr_spawn_chance = 100;
|
||||
}
|
||||
|
||||
bool damage_undead_at(int pos, int damage) {
|
||||
@@ -607,13 +649,15 @@ bool damage_undead_at(int pos, int damage) {
|
||||
}
|
||||
if (undeads[i].undead_type == "undead_resident") {
|
||||
undead_residents_count--;
|
||||
if (undead_residents_count < 0) undead_residents_count = 0;
|
||||
if (undead_residents_count < 0)
|
||||
undead_residents_count = 0;
|
||||
}
|
||||
if (undeads[i].sound_handle != -1) {
|
||||
p.destroy_sound(undeads[i].sound_handle);
|
||||
undeads[i].sound_handle = -1;
|
||||
}
|
||||
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", undeads[i].voice_sound, x, pos, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", undeads[i].voice_sound, x, pos,
|
||||
ZOMBIE_SOUND_VOLUME_STEP);
|
||||
undeads.remove_at(i);
|
||||
}
|
||||
return true;
|
||||
@@ -623,9 +667,19 @@ bool damage_undead_at(int pos, int damage) {
|
||||
}
|
||||
|
||||
// Backward compatibility aliases (to be removed after full refactoring)
|
||||
Undead@[]@ zombies = @undeads; // Array alias for backward compatibility
|
||||
Undead@ get_zombie_at(int pos) { return get_undead_at(pos); }
|
||||
bool damage_zombie_at(int pos, int damage) { return damage_undead_at(pos, damage); }
|
||||
void update_zombies() { update_undeads(); }
|
||||
void clear_zombies() { clear_undeads(); }
|
||||
void spawn_zombie() { spawn_undead("zombie"); }
|
||||
Undead @[] @zombies = @undeads; // Array alias for backward compatibility
|
||||
Undead @get_zombie_at(int pos) {
|
||||
return get_undead_at(pos);
|
||||
}
|
||||
bool damage_zombie_at(int pos, int damage) {
|
||||
return damage_undead_at(pos, damage);
|
||||
}
|
||||
void update_zombies() {
|
||||
update_undeads();
|
||||
}
|
||||
void clear_zombies() {
|
||||
clear_undeads();
|
||||
}
|
||||
void spawn_zombie() {
|
||||
spawn_undead("zombie");
|
||||
}
|
||||
|
||||
+128
-100
@@ -8,7 +8,6 @@ void apply_falling_damage(int fall_height) {
|
||||
p.play_stationary("sounds/actions/hit_ground.ogg", false);
|
||||
|
||||
if (fall_height <= SAFE_FALL_HEIGHT) {
|
||||
speak_with_history("Landed safely.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,13 +19,15 @@ void apply_falling_damage(int fall_height) {
|
||||
|
||||
// Apply damage
|
||||
player_health -= damage;
|
||||
if (player_health < 0) player_health = 0;
|
||||
if (player_health < 0)
|
||||
player_health = 0;
|
||||
if (damage > 0) {
|
||||
play_player_damage_sound();
|
||||
}
|
||||
|
||||
// Feedback
|
||||
speak_with_history("Fell " + fall_height + " feet! Took " + damage + " damage. " + player_health + " health remaining.", true);
|
||||
speak_with_history(
|
||||
"Fell " + fall_height + " feet! Took " + damage + " damage. " + player_health + " health remaining.", true);
|
||||
}
|
||||
// Tree Object
|
||||
class Tree {
|
||||
@@ -74,7 +75,7 @@ class Tree {
|
||||
areaEnd = GRASS_END;
|
||||
}
|
||||
|
||||
Tree@ currentTree = @this;
|
||||
Tree @currentTree = @ this;
|
||||
if (!place_tree_in_area(currentTree, areaStart, areaEnd)) {
|
||||
return;
|
||||
}
|
||||
@@ -111,10 +112,12 @@ class Tree {
|
||||
|
||||
void try_regen() {
|
||||
// Skip if tree is fully stocked
|
||||
if (!depleted && !is_chopped) return;
|
||||
if (!depleted && !is_chopped)
|
||||
return;
|
||||
|
||||
// Check every minute (60000ms)
|
||||
if (regen_timer.elapsed < 60000) return;
|
||||
if (regen_timer.elapsed < 60000)
|
||||
return;
|
||||
|
||||
// Advance to next minute
|
||||
regen_timer.restart();
|
||||
@@ -142,16 +145,21 @@ class Tree {
|
||||
|
||||
// Determine base chance based on minutes elapsed
|
||||
int base_chance = 0;
|
||||
if (minutes_since_depletion == 1) base_chance = 25;
|
||||
else if (minutes_since_depletion == 2) base_chance = 50;
|
||||
else if (minutes_since_depletion == 3) base_chance = 75;
|
||||
else if (minutes_since_depletion == 4) base_chance = 100;
|
||||
if (minutes_since_depletion == 1)
|
||||
base_chance = 25;
|
||||
else if (minutes_since_depletion == 2)
|
||||
base_chance = 50;
|
||||
else if (minutes_since_depletion == 3)
|
||||
base_chance = 75;
|
||||
else if (minutes_since_depletion == 4)
|
||||
base_chance = 100;
|
||||
|
||||
// Try to add items with decreasing probability
|
||||
int current_chance = base_chance;
|
||||
while (current_chance >= 25) {
|
||||
// Check if we can add anything
|
||||
if (sticks >= 3 && vines >= 2) break;
|
||||
if (sticks >= 3 && vines >= 2)
|
||||
break;
|
||||
|
||||
// Roll for success
|
||||
int roll = random(1, 100);
|
||||
@@ -183,8 +191,7 @@ class Tree {
|
||||
is_chopped = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Tree@[] trees;
|
||||
} Tree @[] trees;
|
||||
|
||||
const int SEARCH_POOL_STREAM_BANK = 0;
|
||||
const int SEARCH_POOL_FOREST = 1;
|
||||
@@ -198,7 +205,7 @@ class SearchPool {
|
||||
string[] terrain_tags;
|
||||
}
|
||||
|
||||
SearchPool@[] search_pools;
|
||||
SearchPool @[] search_pools;
|
||||
int[] search_mass_noun_items;
|
||||
|
||||
void init_search_pools() {
|
||||
@@ -209,26 +216,26 @@ void init_search_pools() {
|
||||
search_pools.resize(SEARCH_POOL_COUNT);
|
||||
|
||||
@search_pools[SEARCH_POOL_STREAM_BANK] = SearchPool();
|
||||
search_pools[SEARCH_POOL_STREAM_BANK].item_types = { ITEM_REEDS, ITEM_CLAY };
|
||||
search_pools[SEARCH_POOL_STREAM_BANK].weights = { 30, 70 };
|
||||
search_pools[SEARCH_POOL_STREAM_BANK].found_messages = { "Found a reed.", "Found clay." };
|
||||
search_pools[SEARCH_POOL_STREAM_BANK].terrain_tags = { "stream_bank" };
|
||||
search_pools[SEARCH_POOL_STREAM_BANK].item_types = {ITEM_REEDS, ITEM_CLAY};
|
||||
search_pools[SEARCH_POOL_STREAM_BANK].weights = {30, 70};
|
||||
search_pools[SEARCH_POOL_STREAM_BANK].found_messages = {"Found a reed.", "Found clay."};
|
||||
search_pools[SEARCH_POOL_STREAM_BANK].terrain_tags = {"stream_bank"};
|
||||
|
||||
@search_pools[SEARCH_POOL_FOREST] = SearchPool();
|
||||
search_pools[SEARCH_POOL_FOREST].item_types = { ITEM_STICKS, ITEM_VINES };
|
||||
search_pools[SEARCH_POOL_FOREST].weights = { 1, 1 };
|
||||
search_pools[SEARCH_POOL_FOREST].found_messages = { "Found a stick.", "Found a vine." };
|
||||
search_pools[SEARCH_POOL_FOREST].terrain_tags = { "forest", "deep_forest" };
|
||||
search_pools[SEARCH_POOL_FOREST].item_types = {ITEM_STICKS, ITEM_VINES};
|
||||
search_pools[SEARCH_POOL_FOREST].weights = {1, 1};
|
||||
search_pools[SEARCH_POOL_FOREST].found_messages = {"Found a stick.", "Found a vine."};
|
||||
search_pools[SEARCH_POOL_FOREST].terrain_tags = {"forest", "deep_forest"};
|
||||
|
||||
@search_pools[SEARCH_POOL_STONE_TERRAIN] = SearchPool();
|
||||
search_pools[SEARCH_POOL_STONE_TERRAIN].item_types = { ITEM_STONES };
|
||||
search_pools[SEARCH_POOL_STONE_TERRAIN].weights = { 1 };
|
||||
search_pools[SEARCH_POOL_STONE_TERRAIN].found_messages = { "Found a stone." };
|
||||
search_pools[SEARCH_POOL_STONE_TERRAIN].terrain_tags = { "gravel", "stone", "hard_stone" };
|
||||
search_pools[SEARCH_POOL_STONE_TERRAIN].item_types = {ITEM_STONES};
|
||||
search_pools[SEARCH_POOL_STONE_TERRAIN].weights = {1};
|
||||
search_pools[SEARCH_POOL_STONE_TERRAIN].found_messages = {"Found a stone."};
|
||||
search_pools[SEARCH_POOL_STONE_TERRAIN].terrain_tags = {"gravel", "stone", "hard_stone"};
|
||||
|
||||
// Mass nouns for auto "Found X." fallback (no article).
|
||||
// Add new mass nouns here when adding search items that should not use "a/an".
|
||||
search_mass_noun_items = { ITEM_CLAY };
|
||||
search_mass_noun_items = {ITEM_CLAY};
|
||||
}
|
||||
|
||||
string get_tree_area_terrain(int areaStart, int areaEnd) {
|
||||
@@ -258,7 +265,7 @@ int get_tree_max_for_area(int areaStart, int areaEnd) {
|
||||
return TREE_MAX_PER_AREA;
|
||||
}
|
||||
|
||||
bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out areaEnd, string &out areaTerrain) {
|
||||
bool get_tree_area_bounds_for_position(int pos, int& out areaStart, int& out areaEnd, string& out areaTerrain) {
|
||||
if (pos >= BASE_END + 1 && pos <= GRASS_END) {
|
||||
areaStart = BASE_END + 1;
|
||||
areaEnd = GRASS_END;
|
||||
@@ -271,12 +278,14 @@ bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out are
|
||||
}
|
||||
|
||||
int index = pos - expanded_area_start;
|
||||
if (index < 0 || index >= int(expanded_terrain_types.length())) return false;
|
||||
if (index < 0 || index >= int(expanded_terrain_types.length()))
|
||||
return false;
|
||||
string terrain = expanded_terrain_types[index];
|
||||
if (terrain.find("mountain:") == 0) {
|
||||
terrain = terrain.substr(9);
|
||||
}
|
||||
if (terrain != "grass" && terrain != "forest" && terrain != "deep_forest") return false;
|
||||
if (terrain != "grass" && terrain != "forest" && terrain != "deep_forest")
|
||||
return false;
|
||||
|
||||
int left = index;
|
||||
while (left > 0) {
|
||||
@@ -284,7 +293,8 @@ bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out are
|
||||
if (leftTerrain.find("mountain:") == 0) {
|
||||
leftTerrain = leftTerrain.substr(9);
|
||||
}
|
||||
if (leftTerrain != terrain) break;
|
||||
if (leftTerrain != terrain)
|
||||
break;
|
||||
left--;
|
||||
}
|
||||
|
||||
@@ -295,7 +305,8 @@ bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out are
|
||||
if (rightTerrain.find("mountain:") == 0) {
|
||||
rightTerrain = rightTerrain.substr(9);
|
||||
}
|
||||
if (rightTerrain != terrain) break;
|
||||
if (rightTerrain != terrain)
|
||||
break;
|
||||
right++;
|
||||
}
|
||||
|
||||
@@ -305,10 +316,11 @@ bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out are
|
||||
return true;
|
||||
}
|
||||
|
||||
int count_trees_in_area(int areaStart, int areaEnd, Tree@ ignoreTree) {
|
||||
int count_trees_in_area(int areaStart, int areaEnd, Tree @ignoreTree) {
|
||||
int count = 0;
|
||||
for (uint i = 0; i < trees.length(); i++) {
|
||||
if (@trees[i] is ignoreTree) continue;
|
||||
if (@trees[i] is ignoreTree)
|
||||
continue;
|
||||
if (trees[i].position >= areaStart && trees[i].position <= areaEnd) {
|
||||
count++;
|
||||
}
|
||||
@@ -317,16 +329,19 @@ int count_trees_in_area(int areaStart, int areaEnd, Tree@ ignoreTree) {
|
||||
}
|
||||
|
||||
bool is_near_required_climb(int pos, int radius) {
|
||||
MountainRange@ mountain = get_mountain_at(pos);
|
||||
if (mountain is null) return false;
|
||||
MountainRange @mountain = get_mountain_at(pos);
|
||||
if (mountain is null)
|
||||
return false;
|
||||
|
||||
int startPos = mountain.start_position;
|
||||
int endPos = mountain.end_position;
|
||||
int edgeStart = pos - radius - 1;
|
||||
int edgeEnd = pos + radius;
|
||||
|
||||
if (edgeStart < startPos) edgeStart = startPos;
|
||||
if (edgeEnd > endPos - 1) edgeEnd = endPos - 1;
|
||||
if (edgeStart < startPos)
|
||||
edgeStart = startPos;
|
||||
if (edgeEnd > endPos - 1)
|
||||
edgeEnd = endPos - 1;
|
||||
|
||||
for (int xPos = edgeStart; xPos <= edgeEnd; xPos++) {
|
||||
if (mountain.is_steep_section(xPos, xPos + 1)) {
|
||||
@@ -337,7 +352,7 @@ bool is_near_required_climb(int pos, int radius) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tree_too_close_in_area(int pos, int areaStart, int areaEnd, Tree@ ignoreTree) {
|
||||
bool tree_too_close_in_area(int pos, int areaStart, int areaEnd, Tree @ignoreTree) {
|
||||
// Keep trees away from the base edge
|
||||
if (pos < BASE_END + 5) {
|
||||
return true;
|
||||
@@ -348,8 +363,10 @@ bool tree_too_close_in_area(int pos, int areaStart, int areaEnd, Tree@ ignoreTre
|
||||
}
|
||||
|
||||
for (uint i = 0; i < trees.length(); i++) {
|
||||
if (@trees[i] is ignoreTree) continue;
|
||||
if (trees[i].position < areaStart || trees[i].position > areaEnd) continue;
|
||||
if (@trees[i] is ignoreTree)
|
||||
continue;
|
||||
if (trees[i].position < areaStart || trees[i].position > areaEnd)
|
||||
continue;
|
||||
|
||||
if (abs(trees[i].position - pos) < TREE_MIN_DISTANCE) {
|
||||
return true;
|
||||
@@ -358,7 +375,7 @@ bool tree_too_close_in_area(int pos, int areaStart, int areaEnd, Tree@ ignoreTre
|
||||
return false;
|
||||
}
|
||||
|
||||
bool place_tree_in_area(Tree@ tree, int areaStart, int areaEnd) {
|
||||
bool place_tree_in_area(Tree @tree, int areaStart, int areaEnd) {
|
||||
int maxTrees = get_tree_max_for_area(areaStart, areaEnd);
|
||||
if (count_trees_in_area(areaStart, areaEnd, tree) >= maxTrees) {
|
||||
return false;
|
||||
@@ -388,7 +405,7 @@ bool spawn_tree_in_area(int areaStart, int areaEnd) {
|
||||
if (tree_too_close_in_area(pos, areaStart, areaEnd, null)) {
|
||||
continue;
|
||||
}
|
||||
Tree@ t = Tree(pos);
|
||||
Tree @t = Tree(pos);
|
||||
trees.insert_last(t);
|
||||
return true;
|
||||
}
|
||||
@@ -401,14 +418,15 @@ void spawn_trees(int grass_start, int grass_end) {
|
||||
}
|
||||
}
|
||||
|
||||
void get_tree_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||
void get_tree_areas(int[] @areaStarts, int[] @areaEnds) {
|
||||
areaStarts.resize(0);
|
||||
areaEnds.resize(0);
|
||||
|
||||
areaStarts.insert_last(BASE_END + 1);
|
||||
areaEnds.insert_last(GRASS_END);
|
||||
|
||||
if (expanded_area_start == -1) return;
|
||||
if (expanded_area_start == -1)
|
||||
return;
|
||||
int total = int(expanded_terrain_types.length());
|
||||
int index = 0;
|
||||
while (index < total) {
|
||||
@@ -423,7 +441,8 @@ void get_tree_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||
if (nextTerrain.find("mountain:") == 0) {
|
||||
nextTerrain = nextTerrain.substr(9);
|
||||
}
|
||||
if (nextTerrain != terrain) break;
|
||||
if (nextTerrain != terrain)
|
||||
break;
|
||||
index++;
|
||||
}
|
||||
int segmentEnd = index;
|
||||
@@ -434,10 +453,11 @@ void get_tree_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||
}
|
||||
}
|
||||
|
||||
bool relocate_tree_to_any_area(Tree@ tree, int[]@ areaStarts, int[]@ areaEnds) {
|
||||
bool relocate_tree_to_any_area(Tree @tree, int[] @areaStarts, int[] @areaEnds) {
|
||||
for (uint i = 0; i < areaStarts.length(); i++) {
|
||||
int maxTrees = get_tree_max_for_area(areaStarts[i], areaEnds[i]);
|
||||
if (count_trees_in_area(areaStarts[i], areaEnds[i], tree) >= maxTrees) continue;
|
||||
if (count_trees_in_area(areaStarts[i], areaEnds[i], tree) >= maxTrees)
|
||||
continue;
|
||||
if (place_tree_in_area(tree, areaStarts[i], areaEnds[i])) {
|
||||
return true;
|
||||
}
|
||||
@@ -449,7 +469,8 @@ void normalize_tree_positions() {
|
||||
int[] areaStarts;
|
||||
int[] areaEnds;
|
||||
get_tree_areas(areaStarts, areaEnds);
|
||||
if (areaStarts.length() == 0) return;
|
||||
if (areaStarts.length() == 0)
|
||||
return;
|
||||
|
||||
for (uint i = 0; i < trees.length(); i++) {
|
||||
int areaStart = 0;
|
||||
@@ -480,7 +501,7 @@ void normalize_tree_positions() {
|
||||
|
||||
while (areaTreeIndices.length() > maxTrees) {
|
||||
uint treeIndex = areaTreeIndices[areaTreeIndices.length() - 1];
|
||||
Tree@ tree = trees[treeIndex];
|
||||
Tree @tree = trees[treeIndex];
|
||||
if (!relocate_tree_to_any_area(tree, areaStarts, areaEnds)) {
|
||||
if (tree.sound_handle != -1) {
|
||||
p.destroy_sound(tree.sound_handle);
|
||||
@@ -497,8 +518,8 @@ void normalize_tree_positions() {
|
||||
}
|
||||
|
||||
if (areaTreeIndices.length() == 2) {
|
||||
Tree@ firstTree = trees[areaTreeIndices[0]];
|
||||
Tree@ secondTree = trees[areaTreeIndices[1]];
|
||||
Tree @firstTree = trees[areaTreeIndices[0]];
|
||||
Tree @secondTree = trees[areaTreeIndices[1]];
|
||||
if (abs(firstTree.position - secondTree.position) < TREE_MIN_DISTANCE) {
|
||||
if (!place_tree_in_area(secondTree, areaStart, areaEnd)) {
|
||||
place_tree_in_area(firstTree, areaStart, areaEnd);
|
||||
@@ -514,7 +535,7 @@ void update_environment() {
|
||||
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].try_regen();
|
||||
|
||||
if (limit_audio && !range_overlaps_active_areas(trees[i].position, trees[i].position, areaStarts, areaEnds)) {
|
||||
@@ -528,9 +549,9 @@ void update_environment() {
|
||||
}
|
||||
}
|
||||
|
||||
Tree@ get_tree_at(int target_x) {
|
||||
for(uint i=0; i<trees.length(); i++) {
|
||||
if(trees[i].position == target_x) {
|
||||
Tree @get_tree_at(int target_x) {
|
||||
for (uint i = 0; i < trees.length(); i++) {
|
||||
if (trees[i].position == target_x) {
|
||||
return @trees[i];
|
||||
}
|
||||
}
|
||||
@@ -538,20 +559,20 @@ Tree@ get_tree_at(int target_x) {
|
||||
}
|
||||
|
||||
void damage_tree(int target_x, int damage) {
|
||||
Tree@ target = null;
|
||||
for(uint i=0; i<trees.length(); i++) {
|
||||
if(trees[i].position == target_x) {
|
||||
Tree @target = null;
|
||||
for (uint i = 0; i < trees.length(); i++) {
|
||||
if (trees[i].position == target_x) {
|
||||
@target = @trees[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(@target != null) {
|
||||
if(!target.is_chopped) {
|
||||
if (@target != null) {
|
||||
if (!target.is_chopped) {
|
||||
target.health -= damage;
|
||||
p.play_stationary("sounds/weapons/axe_hit.ogg", false);
|
||||
|
||||
if(target.health <= 0) {
|
||||
if (target.health <= 0) {
|
||||
target.is_chopped = true;
|
||||
target.depleted = true;
|
||||
target.regen_timer.restart();
|
||||
@@ -578,7 +599,8 @@ void damage_tree(int target_x, int damage) {
|
||||
string drop_message = "Tree fell!";
|
||||
if (sticks_added > 0 || vines_added > 0 || logs_added > 0) {
|
||||
string log_label = (logs_added == 1) ? " log" : " logs";
|
||||
drop_message += " Got " + sticks_added + " sticks, " + vines_added + " vines, and " + logs_added + log_label + ".";
|
||||
drop_message += " Got " + sticks_added + " sticks, " + vines_added + " vines, and " + logs_added +
|
||||
log_label + ".";
|
||||
}
|
||||
if (sticks_added < sticks_dropped || vines_added < vines_dropped || logs_added < 1) {
|
||||
drop_message += " Inventory full.";
|
||||
@@ -626,7 +648,8 @@ string get_auto_found_message(int item_type) {
|
||||
}
|
||||
|
||||
string first_letter = singular.substr(0, 1);
|
||||
if (first_letter == "a" || first_letter == "e" || first_letter == "i" || first_letter == "o" || first_letter == "u") {
|
||||
if (first_letter == "a" || first_letter == "e" || first_letter == "i" || first_letter == "o" ||
|
||||
first_letter == "u") {
|
||||
return "Found an " + singular + ".";
|
||||
}
|
||||
return "Found a " + singular + ".";
|
||||
@@ -698,19 +721,18 @@ bool try_search_for_terrain(string terrain_type) {
|
||||
}
|
||||
for (uint j = 0; j < search_pools[i].terrain_tags.length(); j++) {
|
||||
if (search_pools[i].terrain_tags[j] == terrain_type) {
|
||||
return try_find_weighted_resource(search_pools[i].item_types,
|
||||
search_pools[i].weights, search_pools[i].found_messages);
|
||||
return try_find_weighted_resource(search_pools[i].item_types, search_pools[i].weights,
|
||||
search_pools[i].found_messages);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void perform_search(int current_x)
|
||||
{
|
||||
void perform_search(int current_x) {
|
||||
// First priority: Check for world drops on this tile or adjacent
|
||||
for (int check_x = current_x - 1; check_x <= current_x + 1; check_x++) {
|
||||
WorldDrop@ drop = get_drop_at(check_x);
|
||||
WorldDrop @drop = get_drop_at(check_x);
|
||||
if (drop != null) {
|
||||
if (!try_pickup_world_drop(drop)) {
|
||||
return;
|
||||
@@ -725,13 +747,14 @@ void perform_search(int current_x)
|
||||
for (int check_x = current_x - SNARE_COLLECT_RANGE; check_x <= current_x + SNARE_COLLECT_RANGE; check_x++) {
|
||||
// Skip current x? User said "beside". If on top, it breaks.
|
||||
// But if I stand adjacent and shift...
|
||||
if (check_x == current_x) continue; // Safety against collecting own snare you stand on? (Collision happens on move)
|
||||
if (check_x == current_x)
|
||||
continue; // Safety against collecting own snare you stand on? (Collision happens on move)
|
||||
// Actually, collision happens when *moving onto* it. If you placed it, you are on it.
|
||||
// If active is false (just placed), you can pick it up.
|
||||
// If active is true (you moved away), moving back breaks it.
|
||||
// So checking adjacent is correct.
|
||||
|
||||
WorldSnare@ s = get_snare_at(check_x);
|
||||
WorldSnare @s = get_snare_at(check_x);
|
||||
if (s != null) {
|
||||
if (s.has_catch) {
|
||||
if (get_personal_count(ITEM_SMALL_GAME) >= get_personal_stack_limit()) {
|
||||
@@ -791,7 +814,8 @@ void perform_search(int current_x)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (near_stream_bank) break;
|
||||
if (near_stream_bank)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,17 +827,15 @@ void perform_search(int current_x)
|
||||
// Trees (Sticks/Vines) - Check for nearby tree, but only on non-stone terrain
|
||||
// Skip tree search if player is on stone terrain (prioritize stone finding)
|
||||
string search_terrain = get_terrain_at_position(current_x);
|
||||
bool skip_tree_search = (search_terrain == "stone" || search_terrain == "gravel" ||
|
||||
search_terrain == "snow" || search_terrain == "hard_stone");
|
||||
bool skip_tree_search = (search_terrain == "stone" || search_terrain == "gravel" || search_terrain == "snow" ||
|
||||
search_terrain == "hard_stone");
|
||||
|
||||
Tree@ nearest = null;
|
||||
Tree @nearest = null;
|
||||
int nearest_distance = 999;
|
||||
if (!skip_tree_search) {
|
||||
for(uint i=0; i<trees.length(); i++)
|
||||
{
|
||||
for (uint i = 0; i < trees.length(); i++) {
|
||||
int distance = abs(trees[i].position - current_x);
|
||||
if(distance <= 1 && distance < nearest_distance)
|
||||
{
|
||||
if (distance <= 1 && distance < nearest_distance) {
|
||||
nearest_distance = distance;
|
||||
@nearest = @trees[i];
|
||||
if (nearest_distance == 0) {
|
||||
@@ -823,9 +845,8 @@ void perform_search(int current_x)
|
||||
}
|
||||
}
|
||||
|
||||
if(@nearest != null)
|
||||
{
|
||||
if(nearest.is_chopped) {
|
||||
if (@nearest != null) {
|
||||
if (nearest.is_chopped) {
|
||||
speak_with_history("This tree has been cut down.", true);
|
||||
return;
|
||||
}
|
||||
@@ -835,8 +856,7 @@ void perform_search(int current_x)
|
||||
return;
|
||||
}
|
||||
|
||||
if(nearest.sticks > 0 || nearest.vines > 0)
|
||||
{
|
||||
if (nearest.sticks > 0 || nearest.vines > 0) {
|
||||
bool find_stick = (nearest.vines <= 0) || (nearest.sticks > 0 && random(0, 1) == 0);
|
||||
bool took_item = false;
|
||||
|
||||
@@ -881,14 +901,12 @@ void perform_search(int current_x)
|
||||
return;
|
||||
}
|
||||
|
||||
if(nearest.sticks == 0 && nearest.vines == 0) {
|
||||
if (nearest.sticks == 0 && nearest.vines == 0) {
|
||||
nearest.depleted = true;
|
||||
nearest.regen_timer.restart();
|
||||
nearest.minutes_since_depletion = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
speak_with_history("This area has nothing left.", true);
|
||||
}
|
||||
return;
|
||||
@@ -903,7 +921,7 @@ void perform_search(int current_x)
|
||||
|
||||
// Climbing functions
|
||||
void start_climbing_tree(int target_x) {
|
||||
Tree@ tree = get_tree_at(target_x);
|
||||
Tree @tree = get_tree_at(target_x);
|
||||
if (tree == null || tree.is_chopped) {
|
||||
return;
|
||||
}
|
||||
@@ -916,7 +934,8 @@ void start_climbing_tree(int target_x) {
|
||||
}
|
||||
|
||||
void update_climbing() {
|
||||
if (!climbing) return;
|
||||
if (!climbing)
|
||||
return;
|
||||
if (y == climb_target_y) {
|
||||
climbing = false;
|
||||
return;
|
||||
@@ -955,7 +974,8 @@ void update_climbing() {
|
||||
|
||||
void climb_down_tree() {
|
||||
int ground_elevation = get_mountain_elevation_at(x);
|
||||
if (y == ground_elevation || climbing) return;
|
||||
if (y == ground_elevation || climbing)
|
||||
return;
|
||||
|
||||
climbing = true;
|
||||
climb_target_y = ground_elevation;
|
||||
@@ -964,7 +984,8 @@ void climb_down_tree() {
|
||||
}
|
||||
|
||||
void start_falling() {
|
||||
if (y <= 0 || falling) return;
|
||||
if (y <= 0 || falling)
|
||||
return;
|
||||
|
||||
falling = true;
|
||||
fall_start_y = y; // Remember where we started falling from
|
||||
@@ -975,7 +996,8 @@ void start_falling() {
|
||||
}
|
||||
|
||||
void update_falling() {
|
||||
if (!falling) return;
|
||||
if (!falling)
|
||||
return;
|
||||
|
||||
// Get ground level (mountain elevation or 0)
|
||||
int ground_level = get_mountain_elevation_at(x);
|
||||
@@ -995,8 +1017,10 @@ void update_falling() {
|
||||
// Pitch ranges from 100 (high up) to 50 (near ground)
|
||||
float height_above_ground = float(y - ground_level);
|
||||
float pitch_percent = 50.0 + (50.0 * (height_above_ground / 30.0));
|
||||
if (pitch_percent < 50.0) pitch_percent = 50.0;
|
||||
if (pitch_percent > 100.0) pitch_percent = 100.0;
|
||||
if (pitch_percent < 50.0)
|
||||
pitch_percent = 50.0;
|
||||
if (pitch_percent > 100.0)
|
||||
pitch_percent = 100.0;
|
||||
|
||||
fall_sound_handle = p.play_stationary_extended("sounds/actions/falling.ogg", true, 0, 0, 0, pitch_percent);
|
||||
|
||||
@@ -1028,7 +1052,7 @@ void land_on_ground(int ground_level) {
|
||||
|
||||
// Mountain movement check
|
||||
bool can_move_mountain(int from_x, int to_x) {
|
||||
MountainRange@ mountain = get_mountain_at(to_x);
|
||||
MountainRange @mountain = get_mountain_at(to_x);
|
||||
if (mountain is null) {
|
||||
// Not entering a mountain
|
||||
return true;
|
||||
@@ -1066,8 +1090,10 @@ bool can_move_mountain(int from_x, int to_x) {
|
||||
}
|
||||
|
||||
bool can_enter_stream_tile(int pos) {
|
||||
if (!is_deep_stream_at(pos)) return true;
|
||||
if (get_personal_count(ITEM_CANOES) > 0) return true;
|
||||
if (!is_deep_stream_at(pos))
|
||||
return true;
|
||||
if (get_personal_count(ITEM_CANOES) > 0)
|
||||
return true;
|
||||
speak_movement_blocked("You need a canoe to cross deep water.");
|
||||
return false;
|
||||
}
|
||||
@@ -1116,7 +1142,8 @@ void start_rope_climb(bool climbing_up, int target_x, int target_elevation) {
|
||||
}
|
||||
|
||||
void update_rope_climbing() {
|
||||
if (!rope_climbing) return;
|
||||
if (!rope_climbing)
|
||||
return;
|
||||
|
||||
// Check if we're already at the target (shouldn't happen, but safety check)
|
||||
if (y == rope_climb_target_y) {
|
||||
@@ -1168,7 +1195,8 @@ void complete_rope_climb() {
|
||||
}
|
||||
|
||||
void check_rope_climb_fall() {
|
||||
if (!rope_climbing) return;
|
||||
if (!rope_climbing)
|
||||
return;
|
||||
|
||||
if (key_down(KEY_LEFT) || key_down(KEY_RIGHT)) {
|
||||
rope_climb_sound_handle = -1;
|
||||
|
||||
+67
-36
@@ -51,7 +51,7 @@ void reset_fishing_session() {
|
||||
fishing_checks_done = 0;
|
||||
}
|
||||
|
||||
bool get_nearby_stream(int pos, int range, int &out stream_start, int &out stream_end) {
|
||||
bool get_nearby_stream(int pos, int range, int& out stream_start, int& out stream_end) {
|
||||
int best_distance = range + 1;
|
||||
|
||||
// Check regular world streams
|
||||
@@ -89,14 +89,18 @@ bool get_nearby_stream(int pos, int range, int &out stream_start, int &out strea
|
||||
}
|
||||
|
||||
int get_cast_target_position(int origin_x, int stream_start, int stream_end) {
|
||||
if (origin_x < stream_start) return stream_start;
|
||||
if (origin_x > stream_end) return stream_end;
|
||||
if (origin_x < stream_start)
|
||||
return stream_start;
|
||||
if (origin_x > stream_end)
|
||||
return stream_end;
|
||||
return (facing == 1) ? stream_end : stream_start;
|
||||
}
|
||||
|
||||
int get_random_stream_tile() {
|
||||
if (target_stream_start < 0 || target_stream_end < 0) return x;
|
||||
if (target_stream_end < target_stream_start) return target_stream_start;
|
||||
if (target_stream_start < 0 || target_stream_end < 0)
|
||||
return x;
|
||||
if (target_stream_end < target_stream_start)
|
||||
return target_stream_start;
|
||||
return random(target_stream_start, target_stream_end);
|
||||
}
|
||||
|
||||
@@ -105,10 +109,14 @@ string get_random_fish_type() {
|
||||
|
||||
if (is_night) {
|
||||
int roll = random(0, 99);
|
||||
if (roll < 40) return "catfish";
|
||||
else if (roll < 60) return "trout";
|
||||
else if (roll < 80) return "bass";
|
||||
else return "salmon";
|
||||
if (roll < 40)
|
||||
return "catfish";
|
||||
else if (roll < 60)
|
||||
return "trout";
|
||||
else if (roll < 80)
|
||||
return "bass";
|
||||
else
|
||||
return "salmon";
|
||||
}
|
||||
|
||||
return fish_types[random(0, 3)];
|
||||
@@ -116,9 +124,12 @@ string get_random_fish_type() {
|
||||
|
||||
string get_fish_size_label(int weight) {
|
||||
int clamped = clamp_fish_weight(weight);
|
||||
if (clamped <= 7) return "small";
|
||||
if (clamped <= 17) return "medium sized";
|
||||
if (clamped <= 27) return "large";
|
||||
if (clamped <= 7)
|
||||
return "small";
|
||||
if (clamped <= 17)
|
||||
return "medium sized";
|
||||
if (clamped <= 27)
|
||||
return "large";
|
||||
return "monster";
|
||||
}
|
||||
|
||||
@@ -144,7 +155,8 @@ void lose_fish(string message) {
|
||||
}
|
||||
|
||||
void start_casting() {
|
||||
if (is_casting || line_in_water || fish_on_line || is_reeling) return;
|
||||
if (is_casting || line_in_water || fish_on_line || is_reeling)
|
||||
return;
|
||||
if (!fishing_pole_equipped) {
|
||||
speak_with_history("You need a fishing pole equipped.", true);
|
||||
return;
|
||||
@@ -170,11 +182,14 @@ void start_casting() {
|
||||
}
|
||||
|
||||
void update_casting() {
|
||||
if (!is_casting) return;
|
||||
if (cast_move_timer.elapsed < FISHING_CAST_MOVE_MS) return;
|
||||
if (!is_casting)
|
||||
return;
|
||||
if (cast_move_timer.elapsed < FISHING_CAST_MOVE_MS)
|
||||
return;
|
||||
|
||||
cast_move_timer.restart();
|
||||
if (cast_direction == 0) cast_direction = (facing == 1) ? 1 : -1;
|
||||
if (cast_direction == 0)
|
||||
cast_direction = (facing == 1) ? 1 : -1;
|
||||
cast_position += cast_direction;
|
||||
|
||||
int offset = cast_position - cast_origin_x;
|
||||
@@ -194,11 +209,13 @@ void update_casting() {
|
||||
cast_direction = -1;
|
||||
}
|
||||
|
||||
play_1d_with_volume_step("sounds/actions/cast_strength.ogg", x, cast_position, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_1d_with_volume_step("sounds/actions/cast_strength.ogg", x, cast_position, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
void release_cast() {
|
||||
if (!is_casting) return;
|
||||
if (!is_casting)
|
||||
return;
|
||||
|
||||
is_casting = false;
|
||||
stop_fishing_sound();
|
||||
@@ -225,7 +242,8 @@ void release_cast() {
|
||||
}
|
||||
|
||||
void update_waiting_for_fish() {
|
||||
if (!line_in_water) return;
|
||||
if (!line_in_water)
|
||||
return;
|
||||
|
||||
const int check_interval = 1000;
|
||||
int checks_ready = fishing_timer.elapsed / check_interval;
|
||||
@@ -233,7 +251,8 @@ void update_waiting_for_fish() {
|
||||
while (fishing_checks_done < checks_ready) {
|
||||
fishing_checks_done++;
|
||||
catch_chance = FISHING_CATCH_CHANCE_START + (fishing_checks_done - 1) * FISHING_CATCH_CHANCE_STEP;
|
||||
if (catch_chance > FISHING_CATCH_CHANCE_MAX) catch_chance = FISHING_CATCH_CHANCE_MAX;
|
||||
if (catch_chance > FISHING_CATCH_CHANCE_MAX)
|
||||
catch_chance = FISHING_CATCH_CHANCE_MAX;
|
||||
|
||||
if (catch_chance > 0 && random(1, 100) <= catch_chance) {
|
||||
line_in_water = false;
|
||||
@@ -248,7 +267,8 @@ void update_waiting_for_fish() {
|
||||
}
|
||||
|
||||
void start_reeling() {
|
||||
if (!fish_on_line || is_reeling) return;
|
||||
if (!fish_on_line || is_reeling)
|
||||
return;
|
||||
if (reel_position < 0) {
|
||||
reel_position = (line_position >= 0) ? line_position : get_random_stream_tile();
|
||||
}
|
||||
@@ -257,12 +277,15 @@ void start_reeling() {
|
||||
reel_direction = reel_start_direction;
|
||||
cast_move_timer.restart();
|
||||
stop_fishing_sound();
|
||||
play_1d_with_volume_step("sounds/actions/cast_strength.ogg", x, reel_position, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_1d_with_volume_step("sounds/actions/cast_strength.ogg", x, reel_position, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
void update_reeling() {
|
||||
if (!is_reeling) return;
|
||||
if (cast_move_timer.elapsed < FISHING_CAST_MOVE_MS) return;
|
||||
if (!is_reeling)
|
||||
return;
|
||||
if (cast_move_timer.elapsed < FISHING_CAST_MOVE_MS)
|
||||
return;
|
||||
|
||||
cast_move_timer.restart();
|
||||
reel_position += reel_direction;
|
||||
@@ -276,10 +299,13 @@ void update_reeling() {
|
||||
reel_direction = 1;
|
||||
}
|
||||
|
||||
if (reel_position < 0) reel_position = 0;
|
||||
if (reel_position > MAP_SIZE - 1) reel_position = MAP_SIZE - 1;
|
||||
if (reel_position < 0)
|
||||
reel_position = 0;
|
||||
if (reel_position > MAP_SIZE - 1)
|
||||
reel_position = MAP_SIZE - 1;
|
||||
|
||||
play_1d_with_volume_step("sounds/actions/cast_strength.ogg", x, reel_position, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
play_1d_with_volume_step("sounds/actions/cast_strength.ogg", x, reel_position, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
void catch_fish() {
|
||||
@@ -300,19 +326,22 @@ void catch_fish() {
|
||||
play_item_collect_sound(collectSoundItem);
|
||||
|
||||
string fish_name = hooked_fish_type;
|
||||
if (fish_name == "") fish_name = "fish";
|
||||
if (fish_name == "")
|
||||
fish_name = "fish";
|
||||
speak_with_history("Caught a " + size_label + " " + fish_name + ".", true);
|
||||
|
||||
reset_fishing_session();
|
||||
}
|
||||
|
||||
void release_reel() {
|
||||
if (!is_reeling) return;
|
||||
if (!is_reeling)
|
||||
return;
|
||||
|
||||
stop_fishing_sound();
|
||||
is_reeling = false;
|
||||
|
||||
if (!fish_on_line) return;
|
||||
if (!fish_on_line)
|
||||
return;
|
||||
if (reel_position == x) {
|
||||
catch_fish();
|
||||
return;
|
||||
@@ -331,10 +360,10 @@ void release_reel() {
|
||||
reel_start_direction = (reel_position < x) ? 1 : -1;
|
||||
}
|
||||
|
||||
bool before_player = (reel_start_direction == 1 && reel_position < x) ||
|
||||
(reel_start_direction == -1 && reel_position > x);
|
||||
bool past_player = (reel_start_direction == 1 && reel_position > x) ||
|
||||
(reel_start_direction == -1 && reel_position < x);
|
||||
bool before_player =
|
||||
(reel_start_direction == 1 && reel_position < x) || (reel_start_direction == -1 && reel_position > x);
|
||||
bool past_player =
|
||||
(reel_start_direction == 1 && reel_position > x) || (reel_start_direction == -1 && reel_position < x);
|
||||
|
||||
if (past_player) {
|
||||
p.play_stationary("sounds/actions/bad_cast.ogg", false);
|
||||
@@ -357,7 +386,8 @@ void release_reel() {
|
||||
}
|
||||
|
||||
bool handle_fishing_breaks() {
|
||||
if (!line_in_water && !fish_on_line && !is_reeling) return false;
|
||||
if (!line_in_water && !fish_on_line && !is_reeling)
|
||||
return false;
|
||||
|
||||
if (!fishing_pole_equipped) {
|
||||
break_fishing_pole("You switched weapons and your fishing pole broke.");
|
||||
@@ -380,7 +410,8 @@ void update_fishing() {
|
||||
bool ctrl_down = is_ctrl_down();
|
||||
bool ctrl_pressed = is_ctrl_pressed();
|
||||
|
||||
if (handle_fishing_breaks()) return;
|
||||
if (handle_fishing_breaks())
|
||||
return;
|
||||
|
||||
if (fishing_pole_equipped && ctrl_pressed && !is_casting && !line_in_water && !fish_on_line && !is_reeling) {
|
||||
start_casting();
|
||||
|
||||
+46
-34
@@ -6,17 +6,8 @@ const int FYLGJA_STAGE_COUNT = 9;
|
||||
const int FYLGJA_UNICORN = 0;
|
||||
const int UNICORN_TRAMPLE_DAMAGE = 20;
|
||||
|
||||
string[] fylgjaStageNames = {
|
||||
"tenuous",
|
||||
"faint",
|
||||
"stirring",
|
||||
"budding",
|
||||
"kindled",
|
||||
"bound",
|
||||
"sworn",
|
||||
"ascendant",
|
||||
"ultimate"
|
||||
};
|
||||
string[] fylgjaStageNames = {"tenuous", "faint", "stirring", "budding", "kindled",
|
||||
"bound", "sworn", "ascendant", "ultimate"};
|
||||
|
||||
int[] adventureIds = {ADVENTURE_UNICORN};
|
||||
string[] adventureStageTargets = {"unicorn"};
|
||||
@@ -49,50 +40,59 @@ void reset_fylgja_state() {
|
||||
|
||||
int get_adventure_index(int adventureId) {
|
||||
for (uint i = 0; i < adventureIds.length(); i++) {
|
||||
if (adventureIds[i] == adventureId) return int(i);
|
||||
if (adventureIds[i] == adventureId)
|
||||
return int(i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_fylgja_index_for_adventure(int adventureId) {
|
||||
for (uint i = 0; i < fylgjaAdventureIds.length(); i++) {
|
||||
if (fylgjaAdventureIds[i] == adventureId) return int(i);
|
||||
if (fylgjaAdventureIds[i] == adventureId)
|
||||
return int(i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool is_fylgja_unlocked(int fylgjaIndex) {
|
||||
if (fylgjaIndex < 0 || fylgjaIndex >= int(fylgjaAdventureIds.length())) return false;
|
||||
if (fylgjaIndex < 0 || fylgjaIndex >= int(fylgjaAdventureIds.length()))
|
||||
return false;
|
||||
int adventureIndex = get_adventure_index(fylgjaAdventureIds[fylgjaIndex]);
|
||||
if (adventureIndex < 0) return false;
|
||||
if (adventureIndex < 0)
|
||||
return false;
|
||||
return adventureCompletionCounts[adventureIndex] >= FYLGJA_STAGE_COUNT;
|
||||
}
|
||||
|
||||
int get_unlocked_fylgja_count() {
|
||||
int unlockedCount = 0;
|
||||
for (uint i = 0; i < fylgjaNames.length(); i++) {
|
||||
if (is_fylgja_unlocked(int(i))) unlockedCount++;
|
||||
if (is_fylgja_unlocked(int(i)))
|
||||
unlockedCount++;
|
||||
}
|
||||
return unlockedCount;
|
||||
}
|
||||
|
||||
void append_adventure_completion_rewards(int adventureId, string[]@ rewards) {
|
||||
void append_adventure_completion_rewards(int adventureId, string[] @rewards) {
|
||||
int adventureIndex = get_adventure_index(adventureId);
|
||||
if (adventureIndex < 0 || @rewards == null) return;
|
||||
if (adventureIndex < 0 || @rewards == null)
|
||||
return;
|
||||
|
||||
adventureCompletionCounts[adventureIndex]++;
|
||||
int completionCount = adventureCompletionCounts[adventureIndex];
|
||||
|
||||
int stageIndex = completionCount - 1;
|
||||
if (stageIndex < 0) stageIndex = 0;
|
||||
if (stageIndex >= int(fylgjaStageNames.length())) stageIndex = int(fylgjaStageNames.length()) - 1;
|
||||
if (stageIndex < 0)
|
||||
stageIndex = 0;
|
||||
if (stageIndex >= int(fylgjaStageNames.length()))
|
||||
stageIndex = int(fylgjaStageNames.length()) - 1;
|
||||
|
||||
string stageName = fylgjaStageNames[stageIndex];
|
||||
string targetName = adventureStageTargets[adventureIndex];
|
||||
rewards.insert_last("You have a " + stageName + " connection with the " + targetName + ".");
|
||||
|
||||
int fylgjaIndex = get_fylgja_index_for_adventure(adventureId);
|
||||
if (fylgjaIndex == -1) return;
|
||||
if (fylgjaIndex == -1)
|
||||
return;
|
||||
|
||||
if (completionCount >= FYLGJA_STAGE_COUNT) {
|
||||
if (completionCount == FYLGJA_STAGE_COUNT) {
|
||||
@@ -104,9 +104,12 @@ void append_adventure_completion_rewards(int adventureId, string[]@ rewards) {
|
||||
}
|
||||
|
||||
void check_fylgja_menu() {
|
||||
if (!key_pressed(KEY_F)) return;
|
||||
if (fylgjaCharging) return;
|
||||
if (get_unlocked_fylgja_count() == 0) return;
|
||||
if (!key_pressed(KEY_F))
|
||||
return;
|
||||
if (fylgjaCharging)
|
||||
return;
|
||||
if (get_unlocked_fylgja_count() == 0)
|
||||
return;
|
||||
|
||||
if (lastFylgjaDay == current_day) {
|
||||
speak_with_history("You have already used your Fylgja today.", true);
|
||||
@@ -127,7 +130,8 @@ void run_fylgja_menu() {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.length() == 0) return;
|
||||
if (options.length() == 0)
|
||||
return;
|
||||
|
||||
speak_with_history("Fylgja menu.", true);
|
||||
|
||||
@@ -147,14 +151,16 @@ void run_fylgja_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(options.length())) selection = 0;
|
||||
if (selection >= int(options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(options.length()) - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
@@ -182,11 +188,14 @@ bool activate_fylgja(int fylgjaIndex) {
|
||||
}
|
||||
|
||||
bool can_start_unicorn_fylgja_charge() {
|
||||
if (x <= BASE_END) return false;
|
||||
if (x <= BASE_END)
|
||||
return false;
|
||||
int step = (facing == 1) ? 1 : -1;
|
||||
int targetX = x + step;
|
||||
if (targetX < 0 || targetX >= MAP_SIZE) return false;
|
||||
if (should_stop_charge_for_climb_up(x, targetX)) return false;
|
||||
if (targetX < 0 || targetX >= MAP_SIZE)
|
||||
return false;
|
||||
if (should_stop_charge_for_climb_up(x, targetX))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -225,8 +234,9 @@ void start_unicorn_fylgja_charge() {
|
||||
}
|
||||
|
||||
bool should_stop_charge_for_climb_up(int fromX, int toX) {
|
||||
MountainRange@ mountain = get_mountain_at(toX);
|
||||
if (mountain is null) return false;
|
||||
MountainRange @mountain = get_mountain_at(toX);
|
||||
if (mountain is null)
|
||||
return false;
|
||||
|
||||
int elevationChange = mountain.get_elevation_change(fromX, toX);
|
||||
return elevationChange >= MOUNTAIN_STEEP_THRESHOLD;
|
||||
@@ -248,7 +258,8 @@ string get_unicorn_charge_sound(int posX) {
|
||||
|
||||
void update_fylgja_charge_audio() {
|
||||
string soundFile = get_unicorn_charge_sound(x);
|
||||
bool needNewSound = (fylgjaSoundHandle == -1 || !p.sound_is_active(fylgjaSoundHandle) || currentFylgjaSound != soundFile);
|
||||
bool needNewSound =
|
||||
(fylgjaSoundHandle == -1 || !p.sound_is_active(fylgjaSoundHandle) || currentFylgjaSound != soundFile);
|
||||
|
||||
if (needNewSound) {
|
||||
if (fylgjaSoundHandle != -1) {
|
||||
@@ -272,7 +283,8 @@ void stop_fylgja_charge() {
|
||||
}
|
||||
|
||||
void update_fylgja_charge() {
|
||||
if (!fylgjaCharging) return;
|
||||
if (!fylgjaCharging)
|
||||
return;
|
||||
|
||||
if (key_down(KEY_LSHIFT) || key_down(KEY_RSHIFT)) {
|
||||
stop_fylgja_charge();
|
||||
|
||||
+229
-115
@@ -70,8 +70,10 @@ int get_personal_stack_limit() {
|
||||
}
|
||||
|
||||
int get_storage_stack_limit() {
|
||||
if (storage_level <= STORAGE_LEVEL_BASE) return BASE_STORAGE_START_MAX;
|
||||
if (storage_level == STORAGE_LEVEL_UPGRADE_1) return BASE_STORAGE_UPGRADE_1_MAX;
|
||||
if (storage_level <= STORAGE_LEVEL_BASE)
|
||||
return BASE_STORAGE_START_MAX;
|
||||
if (storage_level == STORAGE_LEVEL_UPGRADE_1)
|
||||
return BASE_STORAGE_UPGRADE_1_MAX;
|
||||
return BASE_STORAGE_UPGRADE_2_MAX;
|
||||
}
|
||||
|
||||
@@ -79,14 +81,16 @@ int get_arrow_limit() {
|
||||
// Quiver required to hold arrows
|
||||
// Each quiver holds 12 arrows
|
||||
int quivers = get_personal_count(ITEM_QUIVERS);
|
||||
if (quivers == 0) return 0;
|
||||
if (quivers == 0)
|
||||
return 0;
|
||||
return quivers * ARROW_CAPACITY_PER_QUIVER;
|
||||
}
|
||||
|
||||
void clamp_arrows_to_quiver_limit() {
|
||||
int maxArrows = get_arrow_limit();
|
||||
int currentArrows = get_personal_count(ITEM_ARROWS);
|
||||
if (currentArrows <= maxArrows) return;
|
||||
if (currentArrows <= maxArrows)
|
||||
return;
|
||||
|
||||
set_personal_count(ITEM_ARROWS, maxArrows);
|
||||
if (maxArrows == 0) {
|
||||
@@ -97,40 +101,65 @@ void clamp_arrows_to_quiver_limit() {
|
||||
}
|
||||
|
||||
string get_equipment_name(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR) return "Spear";
|
||||
if (equip_type == EQUIP_AXE) return "Stone Axe";
|
||||
if (equip_type == EQUIP_SLING) return "Sling";
|
||||
if (equip_type == EQUIP_BOW) return "Bow";
|
||||
if (equip_type == EQUIP_HAT) return "Skin Hat";
|
||||
if (equip_type == EQUIP_GLOVES) return "Skin Gloves";
|
||||
if (equip_type == EQUIP_PANTS) return "Skin Pants";
|
||||
if (equip_type == EQUIP_TUNIC) return "Skin Tunic";
|
||||
if (equip_type == EQUIP_MOCCASINS) return "Moccasins";
|
||||
if (equip_type == EQUIP_POUCH) return "Skin Pouch";
|
||||
if (equip_type == EQUIP_BACKPACK) return "Backpack";
|
||||
if (equip_type == EQUIP_FISHING_POLE) return "Fishing Pole";
|
||||
if (equip_type == EQUIP_SPEAR)
|
||||
return "Spear";
|
||||
if (equip_type == EQUIP_AXE)
|
||||
return "Stone Axe";
|
||||
if (equip_type == EQUIP_SLING)
|
||||
return "Sling";
|
||||
if (equip_type == EQUIP_BOW)
|
||||
return "Bow";
|
||||
if (equip_type == EQUIP_HAT)
|
||||
return "Skin Hat";
|
||||
if (equip_type == EQUIP_GLOVES)
|
||||
return "Skin Gloves";
|
||||
if (equip_type == EQUIP_PANTS)
|
||||
return "Skin Pants";
|
||||
if (equip_type == EQUIP_TUNIC)
|
||||
return "Skin Tunic";
|
||||
if (equip_type == EQUIP_MOCCASINS)
|
||||
return "Moccasins";
|
||||
if (equip_type == EQUIP_POUCH)
|
||||
return "Skin Pouch";
|
||||
if (equip_type == EQUIP_BACKPACK)
|
||||
return "Backpack";
|
||||
if (equip_type == EQUIP_FISHING_POLE)
|
||||
return "Fishing Pole";
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
bool equipment_available(int equip_type) {
|
||||
// Check unruned items first, then runed versions
|
||||
if (equip_type == EQUIP_SPEAR) return get_personal_count(ITEM_SPEARS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_AXE) return get_personal_count(ITEM_AXES) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_SLING) return get_personal_count(ITEM_SLINGS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_BOW) return get_personal_count(ITEM_BOWS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_HAT) return get_personal_count(ITEM_SKIN_HATS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_GLOVES) return get_personal_count(ITEM_SKIN_GLOVES) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_PANTS) return get_personal_count(ITEM_SKIN_PANTS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_TUNIC) return get_personal_count(ITEM_SKIN_TUNICS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_MOCCASINS) return get_personal_count(ITEM_MOCCASINS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_POUCH) return get_personal_count(ITEM_SKIN_POUCHES) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_BACKPACK) return get_personal_count(ITEM_BACKPACKS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_FISHING_POLE) return get_personal_count(ITEM_FISHING_POLES) > 0;
|
||||
if (equip_type == EQUIP_SPEAR)
|
||||
return get_personal_count(ITEM_SPEARS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_AXE)
|
||||
return get_personal_count(ITEM_AXES) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_SLING)
|
||||
return get_personal_count(ITEM_SLINGS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_BOW)
|
||||
return get_personal_count(ITEM_BOWS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_HAT)
|
||||
return get_personal_count(ITEM_SKIN_HATS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_GLOVES)
|
||||
return get_personal_count(ITEM_SKIN_GLOVES) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_PANTS)
|
||||
return get_personal_count(ITEM_SKIN_PANTS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_TUNIC)
|
||||
return get_personal_count(ITEM_SKIN_TUNICS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_MOCCASINS)
|
||||
return get_personal_count(ITEM_MOCCASINS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_POUCH)
|
||||
return get_personal_count(ITEM_SKIN_POUCHES) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_BACKPACK)
|
||||
return get_personal_count(ITEM_BACKPACKS) > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_FISHING_POLE)
|
||||
return get_personal_count(ITEM_FISHING_POLES) > 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void equip_equipment_type(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE || equip_type == EQUIP_SLING || equip_type == EQUIP_BOW || equip_type == EQUIP_FISHING_POLE) {
|
||||
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE || equip_type == EQUIP_SLING || equip_type == EQUIP_BOW ||
|
||||
equip_type == EQUIP_FISHING_POLE) {
|
||||
spear_equipped = (equip_type == EQUIP_SPEAR);
|
||||
axe_equipped = (equip_type == EQUIP_AXE);
|
||||
sling_equipped = (equip_type == EQUIP_SLING);
|
||||
@@ -139,28 +168,47 @@ void equip_equipment_type(int equip_type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (equip_type == EQUIP_HAT) equipped_head = EQUIP_HAT;
|
||||
else if (equip_type == EQUIP_TUNIC) equipped_torso = EQUIP_TUNIC;
|
||||
else if (equip_type == EQUIP_GLOVES) equipped_hands = EQUIP_GLOVES;
|
||||
else if (equip_type == EQUIP_PANTS) equipped_legs = EQUIP_PANTS;
|
||||
else if (equip_type == EQUIP_MOCCASINS) equipped_feet = EQUIP_MOCCASINS;
|
||||
else if (equip_type == EQUIP_POUCH) equipped_arms = EQUIP_POUCH;
|
||||
else if (equip_type == EQUIP_BACKPACK) equipped_arms = EQUIP_BACKPACK;
|
||||
if (equip_type == EQUIP_HAT)
|
||||
equipped_head = EQUIP_HAT;
|
||||
else if (equip_type == EQUIP_TUNIC)
|
||||
equipped_torso = EQUIP_TUNIC;
|
||||
else if (equip_type == EQUIP_GLOVES)
|
||||
equipped_hands = EQUIP_GLOVES;
|
||||
else if (equip_type == EQUIP_PANTS)
|
||||
equipped_legs = EQUIP_PANTS;
|
||||
else if (equip_type == EQUIP_MOCCASINS)
|
||||
equipped_feet = EQUIP_MOCCASINS;
|
||||
else if (equip_type == EQUIP_POUCH)
|
||||
equipped_arms = EQUIP_POUCH;
|
||||
else if (equip_type == EQUIP_BACKPACK)
|
||||
equipped_arms = EQUIP_BACKPACK;
|
||||
}
|
||||
|
||||
bool equipment_is_equipped(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR) return spear_equipped;
|
||||
if (equip_type == EQUIP_AXE) return axe_equipped;
|
||||
if (equip_type == EQUIP_SLING) return sling_equipped;
|
||||
if (equip_type == EQUIP_BOW) return bow_equipped;
|
||||
if (equip_type == EQUIP_FISHING_POLE) return fishing_pole_equipped;
|
||||
if (equip_type == EQUIP_HAT) return equipped_head == EQUIP_HAT;
|
||||
if (equip_type == EQUIP_TUNIC) return equipped_torso == EQUIP_TUNIC;
|
||||
if (equip_type == EQUIP_GLOVES) return equipped_hands == EQUIP_GLOVES;
|
||||
if (equip_type == EQUIP_PANTS) return equipped_legs == EQUIP_PANTS;
|
||||
if (equip_type == EQUIP_MOCCASINS) return equipped_feet == EQUIP_MOCCASINS;
|
||||
if (equip_type == EQUIP_POUCH) return equipped_arms == EQUIP_POUCH;
|
||||
if (equip_type == EQUIP_BACKPACK) return equipped_arms == EQUIP_BACKPACK;
|
||||
if (equip_type == EQUIP_SPEAR)
|
||||
return spear_equipped;
|
||||
if (equip_type == EQUIP_AXE)
|
||||
return axe_equipped;
|
||||
if (equip_type == EQUIP_SLING)
|
||||
return sling_equipped;
|
||||
if (equip_type == EQUIP_BOW)
|
||||
return bow_equipped;
|
||||
if (equip_type == EQUIP_FISHING_POLE)
|
||||
return fishing_pole_equipped;
|
||||
if (equip_type == EQUIP_HAT)
|
||||
return equipped_head == EQUIP_HAT;
|
||||
if (equip_type == EQUIP_TUNIC)
|
||||
return equipped_torso == EQUIP_TUNIC;
|
||||
if (equip_type == EQUIP_GLOVES)
|
||||
return equipped_hands == EQUIP_GLOVES;
|
||||
if (equip_type == EQUIP_PANTS)
|
||||
return equipped_legs == EQUIP_PANTS;
|
||||
if (equip_type == EQUIP_MOCCASINS)
|
||||
return equipped_feet == EQUIP_MOCCASINS;
|
||||
if (equip_type == EQUIP_POUCH)
|
||||
return equipped_arms == EQUIP_POUCH;
|
||||
if (equip_type == EQUIP_BACKPACK)
|
||||
return equipped_arms == EQUIP_BACKPACK;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -194,11 +242,16 @@ void unequip_equipment_type(int equip_type) {
|
||||
|
||||
void update_max_health_from_equipment() {
|
||||
int bonus = 0;
|
||||
if (equipped_head == EQUIP_HAT) bonus += HAT_MAX_HEALTH_BONUS;
|
||||
if (equipped_hands == EQUIP_GLOVES) bonus += GLOVES_MAX_HEALTH_BONUS;
|
||||
if (equipped_legs == EQUIP_PANTS) bonus += PANTS_MAX_HEALTH_BONUS;
|
||||
if (equipped_torso == EQUIP_TUNIC) bonus += TUNIC_MAX_HEALTH_BONUS;
|
||||
if (equipped_feet == EQUIP_MOCCASINS) bonus += MOCCASINS_MAX_HEALTH_BONUS;
|
||||
if (equipped_head == EQUIP_HAT)
|
||||
bonus += HAT_MAX_HEALTH_BONUS;
|
||||
if (equipped_hands == EQUIP_GLOVES)
|
||||
bonus += GLOVES_MAX_HEALTH_BONUS;
|
||||
if (equipped_legs == EQUIP_PANTS)
|
||||
bonus += PANTS_MAX_HEALTH_BONUS;
|
||||
if (equipped_torso == EQUIP_TUNIC)
|
||||
bonus += TUNIC_MAX_HEALTH_BONUS;
|
||||
if (equipped_feet == EQUIP_MOCCASINS)
|
||||
bonus += MOCCASINS_MAX_HEALTH_BONUS;
|
||||
max_health = base_max_health + bonus;
|
||||
if (player_health > max_health) {
|
||||
player_health = max_health;
|
||||
@@ -214,25 +267,37 @@ void update_max_health_from_equipment() {
|
||||
// Apply blessing bonus on top of existing speed
|
||||
if (blessing_speed_active) {
|
||||
int blessing_bonus = BASE_WALK_SPEED - BLESSING_WALK_SPEED;
|
||||
if (blessing_bonus < 0) blessing_bonus = 0;
|
||||
if (blessing_bonus < 0)
|
||||
blessing_bonus = 0;
|
||||
walk_speed -= blessing_bonus;
|
||||
}
|
||||
|
||||
// Ensure minimum walk speed
|
||||
if (walk_speed < 200) walk_speed = 200;
|
||||
if (walk_speed < 200)
|
||||
walk_speed = 200;
|
||||
}
|
||||
|
||||
int get_quick_slot_key() {
|
||||
if (key_pressed(KEY_1)) return 1;
|
||||
if (key_pressed(KEY_2)) return 2;
|
||||
if (key_pressed(KEY_3)) return 3;
|
||||
if (key_pressed(KEY_4)) return 4;
|
||||
if (key_pressed(KEY_5)) return 5;
|
||||
if (key_pressed(KEY_6)) return 6;
|
||||
if (key_pressed(KEY_7)) return 7;
|
||||
if (key_pressed(KEY_8)) return 8;
|
||||
if (key_pressed(KEY_9)) return 9;
|
||||
if (key_pressed(KEY_0)) return 0;
|
||||
if (key_pressed(KEY_1))
|
||||
return 1;
|
||||
if (key_pressed(KEY_2))
|
||||
return 2;
|
||||
if (key_pressed(KEY_3))
|
||||
return 3;
|
||||
if (key_pressed(KEY_4))
|
||||
return 4;
|
||||
if (key_pressed(KEY_5))
|
||||
return 5;
|
||||
if (key_pressed(KEY_6))
|
||||
return 6;
|
||||
if (key_pressed(KEY_7))
|
||||
return 7;
|
||||
if (key_pressed(KEY_8))
|
||||
return 8;
|
||||
if (key_pressed(KEY_9))
|
||||
return 9;
|
||||
if (key_pressed(KEY_0))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -279,26 +344,46 @@ string get_equipment_display_name_with_rune(int equip_type, int rune_type) {
|
||||
}
|
||||
|
||||
bool is_breakable_item_type(int itemType) {
|
||||
if (is_runed_item_type(itemType)) return true;
|
||||
if (itemType == ITEM_SPEARS) return true;
|
||||
if (itemType == ITEM_SLINGS) return true;
|
||||
if (itemType == ITEM_AXES) return true;
|
||||
if (itemType == ITEM_SNARES) return true;
|
||||
if (itemType == ITEM_KNIVES) return true;
|
||||
if (itemType == ITEM_FISHING_POLES) return true;
|
||||
if (itemType == ITEM_SKIN_HATS) return true;
|
||||
if (itemType == ITEM_SKIN_GLOVES) return true;
|
||||
if (itemType == ITEM_SKIN_PANTS) return true;
|
||||
if (itemType == ITEM_SKIN_TUNICS) return true;
|
||||
if (itemType == ITEM_MOCCASINS) return true;
|
||||
if (itemType == ITEM_SKIN_POUCHES) return true;
|
||||
if (itemType == ITEM_ROPES) return true;
|
||||
if (itemType == ITEM_REED_BASKETS) return true;
|
||||
if (itemType == ITEM_CLAY_POTS) return true;
|
||||
if (itemType == ITEM_BOWS) return true;
|
||||
if (itemType == ITEM_QUIVERS) return true;
|
||||
if (itemType == ITEM_BACKPACKS) return true;
|
||||
if (itemType == ITEM_CANOES) return true;
|
||||
if (is_runed_item_type(itemType))
|
||||
return true;
|
||||
if (itemType == ITEM_SPEARS)
|
||||
return true;
|
||||
if (itemType == ITEM_SLINGS)
|
||||
return true;
|
||||
if (itemType == ITEM_AXES)
|
||||
return true;
|
||||
if (itemType == ITEM_SNARES)
|
||||
return true;
|
||||
if (itemType == ITEM_KNIVES)
|
||||
return true;
|
||||
if (itemType == ITEM_FISHING_POLES)
|
||||
return true;
|
||||
if (itemType == ITEM_SKIN_HATS)
|
||||
return true;
|
||||
if (itemType == ITEM_SKIN_GLOVES)
|
||||
return true;
|
||||
if (itemType == ITEM_SKIN_PANTS)
|
||||
return true;
|
||||
if (itemType == ITEM_SKIN_TUNICS)
|
||||
return true;
|
||||
if (itemType == ITEM_MOCCASINS)
|
||||
return true;
|
||||
if (itemType == ITEM_SKIN_POUCHES)
|
||||
return true;
|
||||
if (itemType == ITEM_ROPES)
|
||||
return true;
|
||||
if (itemType == ITEM_REED_BASKETS)
|
||||
return true;
|
||||
if (itemType == ITEM_CLAY_POTS)
|
||||
return true;
|
||||
if (itemType == ITEM_BOWS)
|
||||
return true;
|
||||
if (itemType == ITEM_QUIVERS)
|
||||
return true;
|
||||
if (itemType == ITEM_BACKPACKS)
|
||||
return true;
|
||||
if (itemType == ITEM_CANOES)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -312,12 +397,15 @@ string get_breakable_item_name(int itemType) {
|
||||
return get_item_label_singular(itemType);
|
||||
}
|
||||
|
||||
void get_breakable_personal_item_types(int[]@ items) {
|
||||
if (@items == null) return;
|
||||
void get_breakable_personal_item_types(int[] @items) {
|
||||
if (@items == null)
|
||||
return;
|
||||
items.resize(0);
|
||||
for (int itemType = 0; itemType < ITEM_COUNT; itemType++) {
|
||||
if (!is_breakable_item_type(itemType)) continue;
|
||||
if (get_personal_count(itemType) <= 0) continue;
|
||||
if (!is_breakable_item_type(itemType))
|
||||
continue;
|
||||
if (get_personal_count(itemType) <= 0)
|
||||
continue;
|
||||
items.insert_last(itemType);
|
||||
}
|
||||
|
||||
@@ -329,7 +417,8 @@ void get_breakable_personal_item_types(int[]@ items) {
|
||||
for (uint j = 0; j < runeTypes.length(); j++) {
|
||||
int runeType = runeTypes[j];
|
||||
int runedCount = get_runed_item_count(equipType, runeType);
|
||||
if (runedCount <= 0) continue;
|
||||
if (runedCount <= 0)
|
||||
continue;
|
||||
int encoded = encode_runed_item_type(equipType, runeType);
|
||||
items.insert_last(encoded);
|
||||
}
|
||||
@@ -342,7 +431,8 @@ bool remove_breakable_personal_item(int itemType) {
|
||||
int runeType = 0;
|
||||
decode_runed_item_type(itemType, equipType, runeType);
|
||||
int current = get_runed_item_count(equipType, runeType);
|
||||
if (current <= 0) return false;
|
||||
if (current <= 0)
|
||||
return false;
|
||||
remove_runed_item(equipType, runeType);
|
||||
if (get_runed_item_count(equipType, runeType) <= 0 && get_equipped_rune_for_slot(equipType) == runeType) {
|
||||
clear_equipped_rune_for_slot(equipType);
|
||||
@@ -350,19 +440,24 @@ bool remove_breakable_personal_item(int itemType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_breakable_item_type(itemType)) return false;
|
||||
if (get_personal_count(itemType) <= 0) return false;
|
||||
if (!is_breakable_item_type(itemType))
|
||||
return false;
|
||||
if (get_personal_count(itemType) <= 0)
|
||||
return false;
|
||||
add_personal_count(itemType, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_consume_heal_scroll() {
|
||||
if (player_health > 0) return false;
|
||||
if (get_personal_count(ITEM_HEAL_SCROLL) <= 0) return false;
|
||||
if (player_health > 0)
|
||||
return false;
|
||||
if (get_personal_count(ITEM_HEAL_SCROLL) <= 0)
|
||||
return false;
|
||||
|
||||
add_personal_count(ITEM_HEAL_SCROLL, -1);
|
||||
player_health = max_health / 2;
|
||||
if (player_health < 1) player_health = 1;
|
||||
if (player_health < 1)
|
||||
player_health = 1;
|
||||
p.play_stationary("sounds/actions/heal_scroll.ogg", false);
|
||||
return true;
|
||||
}
|
||||
@@ -433,31 +528,43 @@ void check_quick_slot_keys() {
|
||||
}
|
||||
|
||||
int add_to_stack(int current, int amount) {
|
||||
if (amount <= 0) return 0;
|
||||
if (amount <= 0)
|
||||
return 0;
|
||||
int space = get_personal_stack_limit() - current;
|
||||
if (space <= 0) return 0;
|
||||
if (amount > space) return space;
|
||||
if (space <= 0)
|
||||
return 0;
|
||||
if (amount > space)
|
||||
return space;
|
||||
return amount;
|
||||
}
|
||||
|
||||
string format_favor(double value) {
|
||||
if (value < 0) value = 0;
|
||||
if (value < 0)
|
||||
value = 0;
|
||||
int scaled = int((value * 100.0) + 0.5);
|
||||
int wholePart = scaled / 100;
|
||||
int fractionalPart = scaled % 100;
|
||||
|
||||
if (fractionalPart <= 0) return "" + wholePart;
|
||||
if (fractionalPart < 10) return wholePart + ".0" + fractionalPart;
|
||||
if (fractionalPart % 10 == 0) return wholePart + "." + (fractionalPart / 10);
|
||||
if (fractionalPart <= 0)
|
||||
return "" + wholePart;
|
||||
if (fractionalPart < 10)
|
||||
return wholePart + ".0" + fractionalPart;
|
||||
if (fractionalPart % 10 == 0)
|
||||
return wholePart + "." + (fractionalPart / 10);
|
||||
return wholePart + "." + fractionalPart;
|
||||
}
|
||||
|
||||
string get_equipped_weapon_name() {
|
||||
if (spear_equipped) return "Spear";
|
||||
if (axe_equipped) return "Stone Axe";
|
||||
if (sling_equipped) return "Sling";
|
||||
if (bow_equipped) return "Bow";
|
||||
if (fishing_pole_equipped) return "Fishing Pole";
|
||||
if (spear_equipped)
|
||||
return "Spear";
|
||||
if (axe_equipped)
|
||||
return "Stone Axe";
|
||||
if (sling_equipped)
|
||||
return "Sling";
|
||||
if (bow_equipped)
|
||||
return "Bow";
|
||||
if (fishing_pole_equipped)
|
||||
return "Fishing Pole";
|
||||
return "None";
|
||||
}
|
||||
|
||||
@@ -480,14 +587,21 @@ string get_speed_status() {
|
||||
}
|
||||
|
||||
void cleanup_equipment_after_inventory_change() {
|
||||
if (!equipment_available(EQUIP_SPEAR)) spear_equipped = false;
|
||||
if (!equipment_available(EQUIP_AXE)) axe_equipped = false;
|
||||
if (!equipment_available(EQUIP_SLING)) sling_equipped = false;
|
||||
if (!equipment_available(EQUIP_BOW)) bow_equipped = false;
|
||||
if (!equipment_available(EQUIP_FISHING_POLE)) fishing_pole_equipped = false;
|
||||
if (!equipment_available(EQUIP_SPEAR))
|
||||
spear_equipped = false;
|
||||
if (!equipment_available(EQUIP_AXE))
|
||||
axe_equipped = false;
|
||||
if (!equipment_available(EQUIP_SLING))
|
||||
sling_equipped = false;
|
||||
if (!equipment_available(EQUIP_BOW))
|
||||
bow_equipped = false;
|
||||
if (!equipment_available(EQUIP_FISHING_POLE))
|
||||
fishing_pole_equipped = false;
|
||||
|
||||
bool any_weapon_equipped = spear_equipped || axe_equipped || sling_equipped || bow_equipped || fishing_pole_equipped;
|
||||
if (!any_weapon_equipped) equipped_weapon_rune = RUNE_NONE;
|
||||
bool any_weapon_equipped =
|
||||
spear_equipped || axe_equipped || sling_equipped || bow_equipped || fishing_pole_equipped;
|
||||
if (!any_weapon_equipped)
|
||||
equipped_weapon_rune = RUNE_NONE;
|
||||
|
||||
if (!equipment_available(EQUIP_HAT)) {
|
||||
equipped_head = EQUIP_NONE;
|
||||
|
||||
+64
-68
@@ -103,15 +103,20 @@ void init_item_registry() {
|
||||
item_registry[ITEM_AXES] = ItemDefinition(ITEM_AXES, "axes", "axe", "Axes", 1.50);
|
||||
item_registry[ITEM_SNARES] = ItemDefinition(ITEM_SNARES, "snares", "snare", "Snares", 0.50);
|
||||
item_registry[ITEM_KNIVES] = ItemDefinition(ITEM_KNIVES, "knives", "knife", "Knives", 0.80);
|
||||
item_registry[ITEM_FISHING_POLES] = ItemDefinition(ITEM_FISHING_POLES, "fishing poles", "fishing pole", "Fishing Poles", 0.80);
|
||||
item_registry[ITEM_FISHING_POLES] =
|
||||
ItemDefinition(ITEM_FISHING_POLES, "fishing poles", "fishing pole", "Fishing Poles", 0.80);
|
||||
item_registry[ITEM_SKIN_HATS] = ItemDefinition(ITEM_SKIN_HATS, "skin hats", "skin hat", "Skin Hats", 0.60);
|
||||
item_registry[ITEM_SKIN_GLOVES] = ItemDefinition(ITEM_SKIN_GLOVES, "skin gloves", "skin glove", "Skin Gloves", 0.60);
|
||||
item_registry[ITEM_SKIN_GLOVES] =
|
||||
ItemDefinition(ITEM_SKIN_GLOVES, "skin gloves", "skin glove", "Skin Gloves", 0.60);
|
||||
item_registry[ITEM_SKIN_PANTS] = ItemDefinition(ITEM_SKIN_PANTS, "skin pants", "skin pants", "Skin Pants", 1.20);
|
||||
item_registry[ITEM_SKIN_TUNICS] = ItemDefinition(ITEM_SKIN_TUNICS, "skin tunics", "skin tunic", "Skin Tunics", 1.20);
|
||||
item_registry[ITEM_SKIN_TUNICS] =
|
||||
ItemDefinition(ITEM_SKIN_TUNICS, "skin tunics", "skin tunic", "Skin Tunics", 1.20);
|
||||
item_registry[ITEM_MOCCASINS] = ItemDefinition(ITEM_MOCCASINS, "moccasins", "moccasin", "Moccasins", 0.80);
|
||||
item_registry[ITEM_SKIN_POUCHES] = ItemDefinition(ITEM_SKIN_POUCHES, "skin pouches", "skin pouch", "Skin Pouches", 0.80);
|
||||
item_registry[ITEM_SKIN_POUCHES] =
|
||||
ItemDefinition(ITEM_SKIN_POUCHES, "skin pouches", "skin pouch", "Skin Pouches", 0.80);
|
||||
item_registry[ITEM_ROPES] = ItemDefinition(ITEM_ROPES, "ropes", "rope", "Ropes", 0.40);
|
||||
item_registry[ITEM_REED_BASKETS] = ItemDefinition(ITEM_REED_BASKETS, "reed baskets", "reed basket", "Reed Baskets", 0.60);
|
||||
item_registry[ITEM_REED_BASKETS] =
|
||||
ItemDefinition(ITEM_REED_BASKETS, "reed baskets", "reed basket", "Reed Baskets", 0.60);
|
||||
item_registry[ITEM_CLAY_POTS] = ItemDefinition(ITEM_CLAY_POTS, "clay pots", "clay pot", "Clay Pots", 0.70);
|
||||
item_registry[ITEM_FEATHERS] = ItemDefinition(ITEM_FEATHERS, "feathers", "feather", "Feathers", 0.05);
|
||||
item_registry[ITEM_DOWN] = ItemDefinition(ITEM_DOWN, "down", "down", "Down", 0.05);
|
||||
@@ -121,64 +126,36 @@ void init_item_registry() {
|
||||
item_registry[ITEM_QUIVERS] = ItemDefinition(ITEM_QUIVERS, "quivers", "quiver", "Quivers", 1.50);
|
||||
item_registry[ITEM_BOWSTRINGS] = ItemDefinition(ITEM_BOWSTRINGS, "bowstrings", "bowstring", "Bowstrings", 0.20);
|
||||
item_registry[ITEM_SINEW] = ItemDefinition(ITEM_SINEW, "sinew", "piece of sinew", "Sinew", 0.10);
|
||||
item_registry[ITEM_BOAR_CARCASSES] = ItemDefinition(ITEM_BOAR_CARCASSES, "boar carcasses", "boar carcass", "Boar Carcasses", 1.50);
|
||||
item_registry[ITEM_BOAR_CARCASSES] =
|
||||
ItemDefinition(ITEM_BOAR_CARCASSES, "boar carcasses", "boar carcass", "Boar Carcasses", 1.50);
|
||||
item_registry[ITEM_BACKPACKS] = ItemDefinition(ITEM_BACKPACKS, "backpacks", "backpack", "Backpacks", 2.50);
|
||||
item_registry[ITEM_CANOES] = ItemDefinition(ITEM_CANOES, "canoes", "canoe", "Canoes", 4.00);
|
||||
item_registry[ITEM_FISH] = ItemDefinition(ITEM_FISH, "fish", "fish", "Fish", 0.10);
|
||||
item_registry[ITEM_SMOKED_FISH] = ItemDefinition(ITEM_SMOKED_FISH, "smoked fish", "smoked fish", "Smoked Fish", 0.20);
|
||||
item_registry[ITEM_HEAL_SCROLL] = ItemDefinition(ITEM_HEAL_SCROLL, "heal scrolls", "heal scroll", "Heal Scrolls", 0.50);
|
||||
item_registry[ITEM_BASKET_FOOD] = ItemDefinition(ITEM_BASKET_FOOD, "baskets of fruits and nuts", "basket of fruits and nuts", "Baskets of Fruits and Nuts", 0.15);
|
||||
item_registry[ITEM_SMOKED_FISH] =
|
||||
ItemDefinition(ITEM_SMOKED_FISH, "smoked fish", "smoked fish", "Smoked Fish", 0.20);
|
||||
item_registry[ITEM_HEAL_SCROLL] =
|
||||
ItemDefinition(ITEM_HEAL_SCROLL, "heal scrolls", "heal scroll", "Heal Scrolls", 0.50);
|
||||
item_registry[ITEM_BASKET_FOOD] = ItemDefinition(ITEM_BASKET_FOOD, "baskets of fruits and nuts",
|
||||
"basket of fruits and nuts", "Baskets of Fruits and Nuts", 0.15);
|
||||
|
||||
// Define display order for inventory menus
|
||||
// This controls the order items appear in menus
|
||||
inventory_display_order = {
|
||||
// Raw materials
|
||||
ITEM_STICKS,
|
||||
ITEM_VINES,
|
||||
ITEM_REEDS,
|
||||
ITEM_STONES,
|
||||
ITEM_LOGS,
|
||||
ITEM_CLAY,
|
||||
ITEM_STICKS, ITEM_VINES, ITEM_REEDS, ITEM_STONES, ITEM_LOGS, ITEM_CLAY,
|
||||
// Hunting drops
|
||||
ITEM_SMALL_GAME,
|
||||
ITEM_BOAR_CARCASSES,
|
||||
ITEM_MEAT,
|
||||
ITEM_SKINS,
|
||||
ITEM_FEATHERS,
|
||||
ITEM_DOWN,
|
||||
ITEM_SINEW,
|
||||
ITEM_SMALL_GAME, ITEM_BOAR_CARCASSES, ITEM_MEAT, ITEM_SKINS, ITEM_FEATHERS, ITEM_DOWN, ITEM_SINEW,
|
||||
// Food items
|
||||
ITEM_FISH,
|
||||
ITEM_SMOKED_FISH,
|
||||
ITEM_BASKET_FOOD,
|
||||
ITEM_FISH, ITEM_SMOKED_FISH, ITEM_BASKET_FOOD,
|
||||
// Misc items
|
||||
ITEM_INCENSE,
|
||||
ITEM_HEAL_SCROLL,
|
||||
ITEM_INCENSE, ITEM_HEAL_SCROLL,
|
||||
// Weapons
|
||||
ITEM_SPEARS,
|
||||
ITEM_SLINGS,
|
||||
ITEM_AXES,
|
||||
ITEM_BOWS,
|
||||
ITEM_ARROWS,
|
||||
ITEM_QUIVERS,
|
||||
ITEM_BOWSTRINGS,
|
||||
ITEM_SPEARS, ITEM_SLINGS, ITEM_AXES, ITEM_BOWS, ITEM_ARROWS, ITEM_QUIVERS, ITEM_BOWSTRINGS,
|
||||
// Tools
|
||||
ITEM_SNARES,
|
||||
ITEM_KNIVES,
|
||||
ITEM_FISHING_POLES,
|
||||
ITEM_ROPES,
|
||||
ITEM_REED_BASKETS,
|
||||
ITEM_CLAY_POTS,
|
||||
ITEM_CANOES,
|
||||
ITEM_SNARES, ITEM_KNIVES, ITEM_FISHING_POLES, ITEM_ROPES, ITEM_REED_BASKETS, ITEM_CLAY_POTS, ITEM_CANOES,
|
||||
// Clothing
|
||||
ITEM_SKIN_HATS,
|
||||
ITEM_SKIN_GLOVES,
|
||||
ITEM_SKIN_PANTS,
|
||||
ITEM_SKIN_TUNICS,
|
||||
ITEM_MOCCASINS,
|
||||
ITEM_SKIN_POUCHES,
|
||||
ITEM_BACKPACKS
|
||||
};
|
||||
ITEM_SKIN_HATS, ITEM_SKIN_GLOVES, ITEM_SKIN_PANTS, ITEM_SKIN_TUNICS, ITEM_MOCCASINS, ITEM_SKIN_POUCHES,
|
||||
ITEM_BACKPACKS};
|
||||
|
||||
// Initialize inventory arrays
|
||||
personal_inventory.resize(ITEM_COUNT);
|
||||
@@ -202,36 +179,44 @@ void reset_inventory() {
|
||||
|
||||
// Accessor functions for personal inventory
|
||||
int get_personal_count(int item_type) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT) return 0;
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return 0;
|
||||
return personal_inventory[item_type];
|
||||
}
|
||||
|
||||
void set_personal_count(int item_type, int count) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT) return;
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return;
|
||||
personal_inventory[item_type] = count;
|
||||
}
|
||||
|
||||
void add_personal_count(int item_type, int amount) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT) return;
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return;
|
||||
personal_inventory[item_type] += amount;
|
||||
if (personal_inventory[item_type] < 0) personal_inventory[item_type] = 0;
|
||||
if (personal_inventory[item_type] < 0)
|
||||
personal_inventory[item_type] = 0;
|
||||
}
|
||||
|
||||
// Accessor functions for storage inventory
|
||||
int get_storage_count(int item_type) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT) return 0;
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return 0;
|
||||
return storage_inventory[item_type];
|
||||
}
|
||||
|
||||
void set_storage_count(int item_type, int count) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT) return;
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return;
|
||||
storage_inventory[item_type] = count;
|
||||
}
|
||||
|
||||
void add_storage_count(int item_type, int amount) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT) return;
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return;
|
||||
storage_inventory[item_type] += amount;
|
||||
if (storage_inventory[item_type] < 0) storage_inventory[item_type] = 0;
|
||||
if (storage_inventory[item_type] < 0)
|
||||
storage_inventory[item_type] = 0;
|
||||
}
|
||||
|
||||
int get_default_fish_weight() {
|
||||
@@ -239,8 +224,10 @@ int get_default_fish_weight() {
|
||||
}
|
||||
|
||||
int clamp_fish_weight(int weight) {
|
||||
if (weight < FISH_WEIGHT_MIN) return FISH_WEIGHT_MIN;
|
||||
if (weight > FISH_WEIGHT_MAX) return FISH_WEIGHT_MAX;
|
||||
if (weight < FISH_WEIGHT_MIN)
|
||||
return FISH_WEIGHT_MIN;
|
||||
if (weight > FISH_WEIGHT_MAX)
|
||||
return FISH_WEIGHT_MAX;
|
||||
return weight;
|
||||
}
|
||||
|
||||
@@ -253,14 +240,16 @@ void add_storage_fish_weight(int weight) {
|
||||
}
|
||||
|
||||
int pop_personal_fish_weight() {
|
||||
if (personal_fish_weights.length() == 0) return get_default_fish_weight();
|
||||
if (personal_fish_weights.length() == 0)
|
||||
return get_default_fish_weight();
|
||||
int weight = personal_fish_weights[0];
|
||||
personal_fish_weights.remove_at(0);
|
||||
return clamp_fish_weight(weight);
|
||||
}
|
||||
|
||||
int pop_storage_fish_weight() {
|
||||
if (storage_fish_weights.length() == 0) return get_default_fish_weight();
|
||||
if (storage_fish_weights.length() == 0)
|
||||
return get_default_fish_weight();
|
||||
int weight = storage_fish_weights[0];
|
||||
storage_fish_weights.remove_at(0);
|
||||
return clamp_fish_weight(weight);
|
||||
@@ -280,30 +269,37 @@ void move_fish_weights_to_personal(int amount) {
|
||||
|
||||
int get_smoked_fish_yield(int weight) {
|
||||
int clamped = clamp_fish_weight(weight);
|
||||
if (clamped <= 7) return 1;
|
||||
if (clamped <= 17) return 2;
|
||||
if (clamped <= 27) return 3;
|
||||
if (clamped <= 7)
|
||||
return 1;
|
||||
if (clamped <= 17)
|
||||
return 2;
|
||||
if (clamped <= 27)
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
// Item metadata lookups
|
||||
string get_item_label(int item_type) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT) return "items";
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return "items";
|
||||
return item_registry[item_type].name;
|
||||
}
|
||||
|
||||
string get_item_label_singular(int item_type) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT) return "item";
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return "item";
|
||||
return item_registry[item_type].singular;
|
||||
}
|
||||
|
||||
string get_item_display_name(int item_type) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT) return "Unknown";
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return "Unknown";
|
||||
return item_registry[item_type].display_name;
|
||||
}
|
||||
|
||||
double get_item_favor_value(int item_type) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT) return 0.01;
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return 0.01;
|
||||
return item_registry[item_type].favor_value;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
bool learnSoundsConfigured = false;
|
||||
bool docsBrowserConfigured = false;
|
||||
|
||||
void learn_sounds_bridge_speak(const string &in message, bool interrupt) {
|
||||
void learn_sounds_bridge_speak(const string& in message, bool interrupt) {
|
||||
speak_with_history(message, interrupt);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ void learn_sounds_bridge_tick() {
|
||||
}
|
||||
|
||||
void configure_docs_browser_if_needed() {
|
||||
if (docsBrowserConfigured) return;
|
||||
if (docsBrowserConfigured)
|
||||
return;
|
||||
|
||||
docs_browser_set_speak_callback(learn_sounds_bridge_speak);
|
||||
docs_browser_set_tick_callback(learn_sounds_bridge_tick);
|
||||
@@ -26,13 +27,14 @@ void configure_docs_browser_if_needed() {
|
||||
docsBrowserConfigured = true;
|
||||
}
|
||||
|
||||
void add_doc_entries(string[]@ labels, string[]@ paths, int[]@ types) {
|
||||
void add_doc_entries(string[] @labels, string[] @paths, int[] @types) {
|
||||
configure_docs_browser_if_needed();
|
||||
docs_browser_add_entries(labels, paths, types, 1);
|
||||
}
|
||||
|
||||
void configure_learn_sounds_if_needed() {
|
||||
if (learnSoundsConfigured) return;
|
||||
if (learnSoundsConfigured)
|
||||
return;
|
||||
|
||||
learn_sounds_set_speak_callback(learn_sounds_bridge_speak);
|
||||
learn_sounds_set_tick_callback(learn_sounds_bridge_tick);
|
||||
|
||||
+28
-21
@@ -7,8 +7,8 @@ void check_action_menu(int x) {
|
||||
}
|
||||
}
|
||||
|
||||
WorldSnare@ get_snare_within_range(int pos, int range) {
|
||||
WorldSnare@ nearest = null;
|
||||
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);
|
||||
@@ -22,19 +22,23 @@ WorldSnare@ get_snare_within_range(int pos, int range) {
|
||||
|
||||
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";
|
||||
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";
|
||||
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) {
|
||||
void check_fire_status(WorldFire @fire) {
|
||||
if (fire == null) {
|
||||
speak_with_history("No fire nearby.", true);
|
||||
return;
|
||||
@@ -44,7 +48,7 @@ void check_fire_status(WorldFire@ fire) {
|
||||
speak_with_history(label + ". " + estimate + " remaining.", true);
|
||||
}
|
||||
|
||||
void check_snare_status(WorldSnare@ snare) {
|
||||
void check_snare_status(WorldSnare @snare) {
|
||||
if (snare == null) {
|
||||
speak_with_history("No snare nearby.", true);
|
||||
return;
|
||||
@@ -88,7 +92,7 @@ void try_place_snare(int x) {
|
||||
}
|
||||
}
|
||||
|
||||
void try_feed_fire_stick(WorldFire@ fire) {
|
||||
void try_feed_fire_stick(WorldFire @fire) {
|
||||
if (get_personal_count(ITEM_STICKS) > 0 && fire != null) {
|
||||
add_personal_count(ITEM_STICKS, -1);
|
||||
fire.add_fuel(300000); // 5 minutes
|
||||
@@ -97,7 +101,7 @@ void try_feed_fire_stick(WorldFire@ fire) {
|
||||
}
|
||||
}
|
||||
|
||||
void try_feed_fire_vine(WorldFire@ fire) {
|
||||
void try_feed_fire_vine(WorldFire @fire) {
|
||||
if (get_personal_count(ITEM_VINES) > 0 && fire != null) {
|
||||
add_personal_count(ITEM_VINES, -1);
|
||||
fire.add_fuel(60000); // 1 minute
|
||||
@@ -106,7 +110,7 @@ void try_feed_fire_vine(WorldFire@ fire) {
|
||||
}
|
||||
}
|
||||
|
||||
void try_feed_fire_log(WorldFire@ fire) {
|
||||
void try_feed_fire_log(WorldFire @fire) {
|
||||
if (get_personal_count(ITEM_LOGS) > 0 && fire != null) {
|
||||
add_personal_count(ITEM_LOGS, -1);
|
||||
fire.add_fuel(720000); // 12 minutes
|
||||
@@ -136,7 +140,7 @@ void try_burn_incense() {
|
||||
speak_with_history("Incense burning. " + incense_hours_remaining + " hours remaining.", true);
|
||||
}
|
||||
|
||||
void try_feed_fire_stick_max(WorldFire@ fire) {
|
||||
void try_feed_fire_stick_max(WorldFire @fire) {
|
||||
if (get_personal_count(ITEM_STICKS) <= 0 || fire == null) {
|
||||
speak_with_history("No sticks to feed fire.", true);
|
||||
return;
|
||||
@@ -151,7 +155,7 @@ void try_feed_fire_stick_max(WorldFire@ fire) {
|
||||
speak_with_history("Dumped " + amount + " sticks into the fire.", true);
|
||||
}
|
||||
|
||||
void try_feed_fire_vine_max(WorldFire@ fire) {
|
||||
void try_feed_fire_vine_max(WorldFire @fire) {
|
||||
if (get_personal_count(ITEM_VINES) <= 0 || fire == null) {
|
||||
speak_with_history("No vines to feed fire.", true);
|
||||
return;
|
||||
@@ -166,7 +170,7 @@ void try_feed_fire_vine_max(WorldFire@ fire) {
|
||||
speak_with_history("Dumped " + amount + " vines into the fire.", true);
|
||||
}
|
||||
|
||||
void try_feed_fire_log_max(WorldFire@ fire) {
|
||||
void try_feed_fire_log_max(WorldFire @fire) {
|
||||
if (get_personal_count(ITEM_LOGS) <= 0 || fire == null) {
|
||||
speak_with_history("No logs to feed fire.", true);
|
||||
return;
|
||||
@@ -215,10 +219,10 @@ void run_action_menu(int x) {
|
||||
const int check_range = 2;
|
||||
|
||||
// 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;
|
||||
WorldFire@ check_fire = get_fire_within_range(x, check_range);
|
||||
WorldSnare@ check_snare = get_snare_within_range(x, check_range);
|
||||
WorldFire @check_fire = get_fire_within_range(x, check_range);
|
||||
WorldSnare @check_snare = get_snare_within_range(x, check_range);
|
||||
|
||||
// Build menu options dynamically
|
||||
options.insert_last("Place Snare");
|
||||
@@ -261,7 +265,7 @@ void run_action_menu(int x) {
|
||||
string[] filtered_options;
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -271,7 +275,8 @@ void run_action_menu(int x) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
bool filter_changed =
|
||||
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
if (filter_changed) {
|
||||
if (filtered_options.length() == 0) {
|
||||
if (filter_text.length() > 0) {
|
||||
@@ -288,7 +293,8 @@ void run_action_menu(int x) {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
@@ -297,7 +303,8 @@ void run_action_menu(int x) {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(filtered_options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(filtered_options.length()) - 1;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
|
||||
+23
-14
@@ -2,12 +2,14 @@
|
||||
// Functions for sacrificing items at the altar
|
||||
|
||||
string format_altar_favor(double value) {
|
||||
if (value < 0) value = 0;
|
||||
if (value < 0)
|
||||
value = 0;
|
||||
return "" + int(value);
|
||||
}
|
||||
|
||||
void check_altar_menu(int player_x) {
|
||||
if (!key_pressed(KEY_S)) return;
|
||||
if (!key_pressed(KEY_S))
|
||||
return;
|
||||
|
||||
// Must be in base
|
||||
if (player_x > BASE_END) {
|
||||
@@ -40,15 +42,16 @@ void sacrifice_item(int item_type) {
|
||||
if (personal_small_game_types.length() > 0) {
|
||||
personal_small_game_types.remove_at(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
add_personal_count(item_type, -1);
|
||||
}
|
||||
|
||||
cleanup_equipment_after_inventory_change();
|
||||
double favor_gain = get_item_favor_value(item_type);
|
||||
favor += favor_gain;
|
||||
speak_with_history("Sacrificed 1 " + get_item_label_singular(item_type) + ". Favor +" + format_altar_favor(favor_gain) + ". Total " + format_altar_favor(favor) + ".", true);
|
||||
speak_with_history("Sacrificed 1 " + get_item_label_singular(item_type) + ". Favor +" +
|
||||
format_altar_favor(favor_gain) + ". Total " + format_altar_favor(favor) + ".",
|
||||
true);
|
||||
}
|
||||
|
||||
void sacrifice_item_max(int item_type) {
|
||||
@@ -67,8 +70,7 @@ void sacrifice_item_max(int item_type) {
|
||||
if (item_type == ITEM_SMALL_GAME) {
|
||||
set_personal_count(ITEM_SMALL_GAME, 0);
|
||||
personal_small_game_types.resize(0);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
set_personal_count(item_type, 0);
|
||||
}
|
||||
|
||||
@@ -76,7 +78,9 @@ void sacrifice_item_max(int item_type) {
|
||||
double total_favor = favor_per_item * available;
|
||||
favor += total_favor;
|
||||
|
||||
speak_with_history("Sacrificed " + available + " " + get_item_label(item_type) + ". Favor +" + format_altar_favor(total_favor) + ". Total " + format_altar_favor(favor) + ".", true);
|
||||
speak_with_history("Sacrificed " + available + " " + get_item_label(item_type) + ". Favor +" +
|
||||
format_altar_favor(total_favor) + ". Total " + format_altar_favor(favor) + ".",
|
||||
true);
|
||||
}
|
||||
|
||||
void run_altar_menu() {
|
||||
@@ -91,7 +95,7 @@ void run_altar_menu() {
|
||||
string[] filtered_options;
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -101,7 +105,8 @@ void run_altar_menu() {
|
||||
break;
|
||||
}
|
||||
|
||||
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
bool filter_changed =
|
||||
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
if (filter_changed) {
|
||||
if (filtered_options.length() == 0) {
|
||||
if (filter_text.length() > 0) {
|
||||
@@ -118,7 +123,8 @@ void run_altar_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
@@ -127,7 +133,8 @@ void run_altar_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(filtered_options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(filtered_options.length()) - 1;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
@@ -138,7 +145,8 @@ void run_altar_menu() {
|
||||
sacrifice_item(item_types[filtered_indices[selection]]);
|
||||
build_personal_inventory_options(options, item_types);
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
if (filtered_options.length() > 0) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
} else if (filter_text.length() > 0) {
|
||||
@@ -153,7 +161,8 @@ void run_altar_menu() {
|
||||
sacrifice_item_max(item_types[filtered_indices[selection]]);
|
||||
build_personal_inventory_options(options, item_types);
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
if (filtered_options.length() > 0) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
} else if (filter_text.length() > 0) {
|
||||
|
||||
@@ -23,18 +23,24 @@ void run_base_info_menu() {
|
||||
int smoked_fish_in_storage = get_storage_count(ITEM_SMOKED_FISH);
|
||||
int basket_food_in_storage = get_storage_count(ITEM_BASKET_FOOD);
|
||||
int total_food = meat_in_storage + smoked_fish_in_storage + basket_food_in_storage;
|
||||
options.insert_last("Food in storage " + meat_in_storage + " meat, " + smoked_fish_in_storage + " smoked fish, " + basket_food_in_storage + " baskets of fruits and nuts. Total " + total_food + ". Daily use " + daily_food);
|
||||
options.insert_last("Food in storage " + meat_in_storage + " meat, " + smoked_fish_in_storage +
|
||||
" smoked fish, " + basket_food_in_storage + " baskets of fruits and nuts. Total " +
|
||||
total_food + ". Daily use " + daily_food);
|
||||
} else {
|
||||
options.insert_last("Storage not built");
|
||||
}
|
||||
|
||||
options.insert_last(get_base_fire_status());
|
||||
|
||||
if (world_altars.length() > 0) options.insert_last("Altar built");
|
||||
else options.insert_last("Altar not built");
|
||||
if (world_altars.length() > 0)
|
||||
options.insert_last("Altar built");
|
||||
else
|
||||
options.insert_last("Altar not built");
|
||||
|
||||
if (get_herb_garden_at_base() != null) options.insert_last("Herb garden built");
|
||||
else options.insert_last("Herb garden not built");
|
||||
if (get_herb_garden_at_base() != null)
|
||||
options.insert_last("Herb garden built");
|
||||
else
|
||||
options.insert_last("Herb garden not built");
|
||||
|
||||
if (world_pastures.length() > 0) {
|
||||
options.insert_last("Pasture built. Livestock " + livestock_count + " of " + MAX_LIVESTOCK);
|
||||
@@ -57,7 +63,7 @@ void run_base_info_menu() {
|
||||
speak_with_history("Base info. " + filtered_options[selection], true);
|
||||
}
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -67,7 +73,8 @@ void run_base_info_menu() {
|
||||
break;
|
||||
}
|
||||
|
||||
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
bool filter_changed =
|
||||
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
if (filter_changed) {
|
||||
if (filtered_options.length() == 0) {
|
||||
if (filter_text.length() > 0) {
|
||||
@@ -84,7 +91,8 @@ void run_base_info_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
@@ -93,7 +101,8 @@ void run_base_info_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(filtered_options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(filtered_options.length()) - 1;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
|
||||
+108
-17
@@ -1,25 +1,88 @@
|
||||
// Character info display
|
||||
// Functions for displaying character stats and equipment
|
||||
|
||||
bool run_pet_abandon_confirm_menu() {
|
||||
if (!petActive) {
|
||||
speak_with_history("No pet.", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] options;
|
||||
options.insert_last("No");
|
||||
options.insert_last("Yes");
|
||||
int selection = 0;
|
||||
|
||||
speak_with_history("Really abandon your pet? " + options[selection], true);
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return false;
|
||||
}
|
||||
if (key_pressed(KEY_ESCAPE)) {
|
||||
speak_with_history("Canceled.", true);
|
||||
return false;
|
||||
}
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0)
|
||||
selection = int(options.length()) - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
play_menu_select_sound();
|
||||
if (selection == 1) {
|
||||
return abandon_pet();
|
||||
}
|
||||
speak_with_history("Canceled.", true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void run_character_info_menu() {
|
||||
string[] equipped_clothing;
|
||||
string[] missing_slots;
|
||||
|
||||
if (equipped_head == EQUIP_HAT) equipped_clothing.insert_last("Skin Hat");
|
||||
else missing_slots.insert_last("head");
|
||||
if (equipped_torso == EQUIP_TUNIC) equipped_clothing.insert_last("Skin Tunic");
|
||||
else missing_slots.insert_last("torso");
|
||||
if (equipped_arms == EQUIP_POUCH) equipped_clothing.insert_last("Skin Pouch");
|
||||
else if (equipped_arms == EQUIP_BACKPACK) equipped_clothing.insert_last("Backpack");
|
||||
else missing_slots.insert_last("arms");
|
||||
if (equipped_hands == EQUIP_GLOVES) equipped_clothing.insert_last("Skin Gloves");
|
||||
else missing_slots.insert_last("hands");
|
||||
if (equipped_legs == EQUIP_PANTS) equipped_clothing.insert_last("Skin Pants");
|
||||
else missing_slots.insert_last("legs");
|
||||
if (equipped_feet == EQUIP_MOCCASINS) equipped_clothing.insert_last("Moccasins");
|
||||
else missing_slots.insert_last("feet");
|
||||
if (equipped_head == EQUIP_HAT)
|
||||
equipped_clothing.insert_last("Skin Hat");
|
||||
else
|
||||
missing_slots.insert_last("head");
|
||||
if (equipped_torso == EQUIP_TUNIC)
|
||||
equipped_clothing.insert_last("Skin Tunic");
|
||||
else
|
||||
missing_slots.insert_last("torso");
|
||||
if (equipped_arms == EQUIP_POUCH)
|
||||
equipped_clothing.insert_last("Skin Pouch");
|
||||
else if (equipped_arms == EQUIP_BACKPACK)
|
||||
equipped_clothing.insert_last("Backpack");
|
||||
else
|
||||
missing_slots.insert_last("arms");
|
||||
if (equipped_hands == EQUIP_GLOVES)
|
||||
equipped_clothing.insert_last("Skin Gloves");
|
||||
else
|
||||
missing_slots.insert_last("hands");
|
||||
if (equipped_legs == EQUIP_PANTS)
|
||||
equipped_clothing.insert_last("Skin Pants");
|
||||
else
|
||||
missing_slots.insert_last("legs");
|
||||
if (equipped_feet == EQUIP_MOCCASINS)
|
||||
equipped_clothing.insert_last("Moccasins");
|
||||
else
|
||||
missing_slots.insert_last("feet");
|
||||
|
||||
string[] options;
|
||||
int petOptionIndex = -1;
|
||||
if (player_name != "") {
|
||||
string sex_label = (player_sex == SEX_FEMALE) ? "Female" : "Male";
|
||||
options.insert_last("Name " + player_name + ". Sex " + sex_label + ".");
|
||||
@@ -46,6 +109,7 @@ void run_character_info_menu() {
|
||||
petInfo += " Knocked out. " + petKnockoutHoursRemaining + " " + hourLabel + " remaining.";
|
||||
}
|
||||
options.insert_last(petInfo);
|
||||
petOptionIndex = options.length() - 1;
|
||||
} else {
|
||||
options.insert_last("Pet none.");
|
||||
}
|
||||
@@ -61,7 +125,7 @@ void run_character_info_menu() {
|
||||
speak_with_history("Character info. " + filtered_options[selection], true);
|
||||
}
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -71,7 +135,8 @@ void run_character_info_menu() {
|
||||
break;
|
||||
}
|
||||
|
||||
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
bool filter_changed =
|
||||
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
if (filter_changed) {
|
||||
if (filtered_options.length() == 0) {
|
||||
if (filter_text.length() > 0) {
|
||||
@@ -88,7 +153,8 @@ void run_character_info_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
@@ -97,10 +163,35 @@ void run_character_info_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(filtered_options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(filtered_options.length()) - 1;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
if (filtered_options.length() == 0)
|
||||
continue;
|
||||
|
||||
int optionIndex = filtered_indices[selection];
|
||||
if (optionIndex == petOptionIndex && petActive) {
|
||||
if (is_pet_knocked_out()) {
|
||||
speak_with_history(
|
||||
"Your " + get_pet_display_name() + " is unconscious. You can't abandon it right now.", true);
|
||||
continue;
|
||||
}
|
||||
|
||||
play_menu_select_sound();
|
||||
if (run_pet_abandon_confirm_menu()) {
|
||||
return;
|
||||
}
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = int(filtered_options.length()) - 1;
|
||||
if (selection >= 0 && selection < int(filtered_options.length())) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,10 @@ bool has_any_equipment() {
|
||||
// Check unruned items
|
||||
if (get_personal_count(ITEM_SPEARS) > 0 || get_personal_count(ITEM_AXES) > 0 ||
|
||||
get_personal_count(ITEM_SLINGS) > 0 || get_personal_count(ITEM_BOWS) > 0 ||
|
||||
get_personal_count(ITEM_FISHING_POLES) > 0 ||
|
||||
get_personal_count(ITEM_SKIN_HATS) > 0 || get_personal_count(ITEM_SKIN_GLOVES) > 0 ||
|
||||
get_personal_count(ITEM_SKIN_PANTS) > 0 || get_personal_count(ITEM_SKIN_TUNICS) > 0 ||
|
||||
get_personal_count(ITEM_MOCCASINS) > 0 || get_personal_count(ITEM_SKIN_POUCHES) > 0 ||
|
||||
get_personal_count(ITEM_BACKPACKS) > 0) {
|
||||
get_personal_count(ITEM_FISHING_POLES) > 0 || get_personal_count(ITEM_SKIN_HATS) > 0 ||
|
||||
get_personal_count(ITEM_SKIN_GLOVES) > 0 || get_personal_count(ITEM_SKIN_PANTS) > 0 ||
|
||||
get_personal_count(ITEM_SKIN_TUNICS) > 0 || get_personal_count(ITEM_MOCCASINS) > 0 ||
|
||||
get_personal_count(ITEM_SKIN_POUCHES) > 0 || get_personal_count(ITEM_BACKPACKS) > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -50,7 +49,8 @@ string get_full_equipment_name(int equip_type, int rune_type) {
|
||||
|
||||
// Check if an item with specific rune is equipped
|
||||
bool is_runed_item_equipped(int equip_type, int rune_type) {
|
||||
if (!equipment_is_equipped(equip_type)) return false;
|
||||
if (!equipment_is_equipped(equip_type))
|
||||
return false;
|
||||
return get_equipped_rune_for_slot(equip_type) == rune_type;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,8 @@ void run_equipment_menu() {
|
||||
for (uint j = 0; j < all_rune_types.length(); j++) {
|
||||
int rune_type = all_rune_types[j];
|
||||
int count = get_runed_item_count(equip_type, rune_type);
|
||||
if (count <= 0) continue;
|
||||
if (count <= 0)
|
||||
continue;
|
||||
string name = get_full_equipment_name(equip_type, rune_type);
|
||||
string status = is_runed_item_equipped(equip_type, rune_type) ? " (equipped)" : "";
|
||||
options.insert_last(name + status);
|
||||
@@ -158,7 +159,7 @@ void run_equipment_menu() {
|
||||
string[] filtered_options;
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -168,7 +169,8 @@ void run_equipment_menu() {
|
||||
break;
|
||||
}
|
||||
|
||||
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
bool filter_changed =
|
||||
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
if (filter_changed) {
|
||||
if (filtered_options.length() == 0) {
|
||||
if (filter_text.length() > 0) {
|
||||
@@ -185,7 +187,8 @@ void run_equipment_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
@@ -194,7 +197,8 @@ void run_equipment_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(filtered_options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(filtered_options.length()) - 1;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Personal inventory menu system
|
||||
// Functions for displaying and managing personal inventory
|
||||
|
||||
void build_personal_inventory_options(string[]@ options, int[]@ item_types) {
|
||||
void build_personal_inventory_options(string[] @options, int[] @item_types) {
|
||||
options.resize(0);
|
||||
item_types.resize(0);
|
||||
|
||||
@@ -23,7 +23,8 @@ void build_personal_inventory_options(string[]@ options, int[]@ item_types) {
|
||||
for (uint j = 0; j < rune_types.length(); j++) {
|
||||
int rune_type = rune_types[j];
|
||||
int count = get_runed_item_count(equip_type, rune_type);
|
||||
if (count <= 0) continue;
|
||||
if (count <= 0)
|
||||
continue;
|
||||
string name = get_runed_item_display_name(equip_type, rune_type);
|
||||
options.insert_last(name + ": " + count);
|
||||
item_types.insert_last(encode_runed_item_type(equip_type, rune_type));
|
||||
@@ -40,7 +41,8 @@ void show_inventory() {
|
||||
int item_type = inventory_display_order[i];
|
||||
int count = get_personal_count(item_type);
|
||||
if (count > 0) {
|
||||
if (!first) info += ", ";
|
||||
if (!first)
|
||||
info += ", ";
|
||||
info += count + " " + get_item_label(item_type);
|
||||
first = false;
|
||||
}
|
||||
@@ -60,8 +62,10 @@ void show_inventory() {
|
||||
for (uint j = 0; j < rune_types.length(); j++) {
|
||||
int rune_type = rune_types[j];
|
||||
int count = get_runed_item_count(equip_type, rune_type);
|
||||
if (count <= 0) continue;
|
||||
if (runed_info.length() > 0) runed_info += ", ";
|
||||
if (count <= 0)
|
||||
continue;
|
||||
if (runed_info.length() > 0)
|
||||
runed_info += ", ";
|
||||
runed_info += count + " " + get_runed_item_display_name(equip_type, rune_type);
|
||||
}
|
||||
}
|
||||
@@ -79,7 +83,7 @@ void run_inventory_root_menu() {
|
||||
int selection = 0;
|
||||
string[] options = {"Personal inventory", "Base storage"};
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -92,21 +96,25 @@ void run_inventory_root_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= options.length()) selection = 0;
|
||||
if (selection >= options.length())
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = options.length() - 1;
|
||||
if (selection < 0)
|
||||
selection = options.length() - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
play_menu_select_sound();
|
||||
if (selection == 0) run_inventory_menu(true);
|
||||
else run_storage_menu();
|
||||
if (selection == 0)
|
||||
run_inventory_menu(true);
|
||||
else
|
||||
run_storage_menu();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -124,7 +132,7 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
string[] filtered_options;
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -134,7 +142,8 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
bool filter_changed =
|
||||
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
if (filter_changed) {
|
||||
if (filtered_options.length() == 0) {
|
||||
if (filter_text.length() > 0) {
|
||||
@@ -151,7 +160,8 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
@@ -160,7 +170,8 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(filtered_options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(filtered_options.length()) - 1;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
@@ -181,7 +192,8 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
deposit_item(item_types[filtered_indices[selection]]);
|
||||
build_personal_inventory_options(options, item_types);
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
if (filtered_options.length() > 0) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
} else if (filter_text.length() > 0) {
|
||||
@@ -196,7 +208,8 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
deposit_item_max(item_types[filtered_indices[selection]]);
|
||||
build_personal_inventory_options(options, item_types);
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
if (filtered_options.length() > 0) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
} else if (filter_text.length() > 0) {
|
||||
|
||||
@@ -28,7 +28,7 @@ bool menu_background_tick() {
|
||||
update_notifications();
|
||||
|
||||
// Fire damage check (only if not jumping)
|
||||
WorldFire@ fire_on_tile = get_fire_at(x);
|
||||
WorldFire @fire_on_tile = get_fire_at(x);
|
||||
if (fire_on_tile != null && !jumping && fire_damage_timer.elapsed > 1000) {
|
||||
player_health--;
|
||||
fire_damage_timer.restart();
|
||||
@@ -37,7 +37,7 @@ bool menu_background_tick() {
|
||||
|
||||
// Healing in base area
|
||||
if (x <= BASE_END && player_health < max_health) {
|
||||
WorldHerbGarden@ herb_garden = get_herb_garden_at_base();
|
||||
WorldHerbGarden @herb_garden = get_herb_garden_at_base();
|
||||
int heal_interval = (herb_garden != null) ? 30000 : 150000; // 30 seconds with garden, 2.5 minutes without
|
||||
|
||||
if (healing_timer.elapsed > heal_interval) {
|
||||
@@ -62,18 +62,21 @@ bool menu_background_tick() {
|
||||
|
||||
void play_menu_move_sound() {
|
||||
string soundFile = "sounds/menu/menu_move.ogg";
|
||||
if (!file_exists(soundFile)) return;
|
||||
if (!audio_asset_exists(soundFile))
|
||||
return;
|
||||
p.play_stationary(soundFile, false);
|
||||
}
|
||||
|
||||
void play_menu_select_sound() {
|
||||
string soundFile = "sounds/menu/menu_select.ogg";
|
||||
if (!file_exists(soundFile)) return;
|
||||
if (!audio_asset_exists(soundFile))
|
||||
return;
|
||||
p.play_stationary(soundFile, false);
|
||||
}
|
||||
|
||||
string join_string_list(const string[]@ items) {
|
||||
if (@items == null || items.length() == 0) return "";
|
||||
string join_string_list(const string[] @items) {
|
||||
if (@items == null || items.length() == 0)
|
||||
return "";
|
||||
string result = items[0];
|
||||
for (uint i = 1; i < items.length(); i++) {
|
||||
result += ", " + items[i];
|
||||
@@ -100,7 +103,8 @@ string get_base_fire_status() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (total == 0) return "No fires in base";
|
||||
if (total == 0)
|
||||
return "No fires in base";
|
||||
return "Fires in base: " + burning + " burning, " + total + " total";
|
||||
}
|
||||
|
||||
@@ -108,10 +112,12 @@ string get_menu_filter_letter() {
|
||||
return menu_get_filter_letter();
|
||||
}
|
||||
|
||||
void apply_menu_filter(const string &in filter_text, const string[]@ options, int[]@ filtered_indices, string[]@ filtered_options) {
|
||||
void apply_menu_filter(const string& in filter_text, const string[] @options, int[] @filtered_indices,
|
||||
string[] @filtered_options) {
|
||||
menu_apply_prefix_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
}
|
||||
|
||||
bool update_menu_filter_state(string &inout filter_text, const string[]@ options, int[]@ filtered_indices, string[]@ filtered_options, int &inout selection) {
|
||||
bool update_menu_filter_state(string& inout filter_text, const string[] @options, int[] @filtered_indices,
|
||||
string[] @filtered_options, int& inout selection) {
|
||||
return menu_update_prefix_filter(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
}
|
||||
|
||||
+22
-12
@@ -34,8 +34,10 @@ void move_fish_to_personal(int amount) {
|
||||
int prompt_transfer_amount(const string prompt, int max_amount) {
|
||||
string input = ui_input_box("Inventory", prompt + " (max " + max_amount + ")", "");
|
||||
int amount = parse_int(input);
|
||||
if (amount <= 0) return 0;
|
||||
if (amount > max_amount) amount = max_amount;
|
||||
if (amount <= 0)
|
||||
return 0;
|
||||
if (amount > max_amount)
|
||||
amount = max_amount;
|
||||
return amount;
|
||||
}
|
||||
|
||||
@@ -70,7 +72,8 @@ void deposit_item(int item_type) {
|
||||
}
|
||||
int max_transfer = (available < capacity) ? available : capacity;
|
||||
int amount = prompt_transfer_amount("Deposit how many?", max_transfer);
|
||||
if (amount <= 0) return;
|
||||
if (amount <= 0)
|
||||
return;
|
||||
|
||||
// Transfer the items
|
||||
add_personal_count(item_type, -amount);
|
||||
@@ -177,7 +180,8 @@ void withdraw_item(int item_type) {
|
||||
}
|
||||
int max_transfer = (available < capacity) ? available : capacity;
|
||||
int amount = prompt_transfer_amount("Withdraw how many?", max_transfer);
|
||||
if (amount <= 0) return;
|
||||
if (amount <= 0)
|
||||
return;
|
||||
|
||||
// Transfer the items
|
||||
add_storage_count(item_type, -amount);
|
||||
@@ -256,7 +260,7 @@ void withdraw_item_max(int item_type) {
|
||||
speak_with_history("Withdrew " + amount + " " + get_item_label(item_type) + ".", true);
|
||||
}
|
||||
|
||||
void build_storage_inventory_options(string[]@ options, int[]@ item_types) {
|
||||
void build_storage_inventory_options(string[] @options, int[] @item_types) {
|
||||
options.resize(0);
|
||||
item_types.resize(0);
|
||||
|
||||
@@ -278,7 +282,8 @@ void build_storage_inventory_options(string[]@ options, int[]@ item_types) {
|
||||
for (uint j = 0; j < rune_types.length(); j++) {
|
||||
int rune_type = rune_types[j];
|
||||
int count = get_stored_runed_item_count(equip_type, rune_type);
|
||||
if (count <= 0) continue;
|
||||
if (count <= 0)
|
||||
continue;
|
||||
string name = get_runed_item_display_name(equip_type, rune_type);
|
||||
options.insert_last(name + ": " + count);
|
||||
item_types.insert_last(encode_runed_item_type(equip_type, rune_type));
|
||||
@@ -303,7 +308,7 @@ void run_storage_menu() {
|
||||
string[] filtered_options;
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -313,7 +318,8 @@ void run_storage_menu() {
|
||||
break;
|
||||
}
|
||||
|
||||
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
bool filter_changed =
|
||||
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
|
||||
if (filter_changed) {
|
||||
if (filtered_options.length() == 0) {
|
||||
if (filter_text.length() > 0) {
|
||||
@@ -330,7 +336,8 @@ void run_storage_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
@@ -339,7 +346,8 @@ void run_storage_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(filtered_options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(filtered_options.length()) - 1;
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
}
|
||||
}
|
||||
@@ -350,7 +358,8 @@ void run_storage_menu() {
|
||||
withdraw_item(item_types[filtered_indices[selection]]);
|
||||
build_storage_inventory_options(options, item_types);
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
if (filtered_options.length() > 0) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
} else if (filter_text.length() > 0) {
|
||||
@@ -365,7 +374,8 @@ void run_storage_menu() {
|
||||
withdraw_item_max(item_types[filtered_indices[selection]]);
|
||||
build_storage_inventory_options(options, item_types);
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
if (selection >= int(filtered_options.length())) selection = 0;
|
||||
if (selection >= int(filtered_options.length()))
|
||||
selection = 0;
|
||||
if (filtered_options.length() > 0) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
} else if (filter_text.length() > 0) {
|
||||
|
||||
@@ -6,12 +6,13 @@ const string NOTIFICATION_SOUND_PATH = "sounds/notify";
|
||||
|
||||
bool notificationsCompatConfigured = false;
|
||||
|
||||
void notify_compat_speak(const string &in message, bool interrupt) {
|
||||
void notify_compat_speak(const string& in message, bool interrupt) {
|
||||
speak_with_history(message, interrupt);
|
||||
}
|
||||
|
||||
void configure_notification_compat_if_needed() {
|
||||
if (notificationsCompatConfigured) return;
|
||||
if (notificationsCompatConfigured)
|
||||
return;
|
||||
|
||||
notifications_set_max_history(NOTIFICATION_HISTORY_LIMIT);
|
||||
notifications_set_delay_ms(NOTIFICATION_DELAY_MS);
|
||||
|
||||
+268
-154
@@ -43,7 +43,8 @@ string petLeavingName = "";
|
||||
string[] petSoundPaths;
|
||||
bool petSoundsInitialized = false;
|
||||
|
||||
funcdef bool PetAdventureFindTargetCallback(int originPos, int referencePos, int &out targetPos, string &out targetLabel, int &out targetKind);
|
||||
funcdef bool PetAdventureFindTargetCallback(int originPos, int referencePos, int& out targetPos,
|
||||
string& out targetLabel, int& out targetKind);
|
||||
funcdef bool PetAdventureDamageCallback(int targetKind, int targetPos, int damage);
|
||||
|
||||
bool petAdventureMode = false;
|
||||
@@ -51,14 +52,14 @@ int petAdventurePlayerPos = -1;
|
||||
bool petAdventurePreOut = false;
|
||||
int petAdventurePrePosition = 0;
|
||||
bool petAdventurePrePositionValid = false;
|
||||
PetAdventureFindTargetCallback@ petAdventureFindTarget = null;
|
||||
PetAdventureDamageCallback@ petAdventureDamageTarget = null;
|
||||
PetAdventureFindTargetCallback @petAdventureFindTarget = null;
|
||||
PetAdventureDamageCallback @petAdventureDamageTarget = null;
|
||||
|
||||
string normalize_pet_path(const string&in path) {
|
||||
string normalize_pet_path(const string& in path) {
|
||||
return path.replace("\\", "/", true);
|
||||
}
|
||||
|
||||
string collapse_pet_spaces(const string&in text) {
|
||||
string collapse_pet_spaces(const string& in text) {
|
||||
string result = text;
|
||||
while (result.find_first(" ") > -1) {
|
||||
result = result.replace(" ", " ", true);
|
||||
@@ -66,7 +67,7 @@ string collapse_pet_spaces(const string&in text) {
|
||||
return result;
|
||||
}
|
||||
|
||||
string normalize_pet_name_text(const string&in raw) {
|
||||
string normalize_pet_name_text(const string& in raw) {
|
||||
string name = raw;
|
||||
name = name.replace("_", " ", true);
|
||||
name = name.replace("-", " ", true);
|
||||
@@ -75,15 +76,15 @@ string normalize_pet_name_text(const string&in raw) {
|
||||
return name;
|
||||
}
|
||||
|
||||
void gather_pet_sound_files(const string&in basePath, string[]@ outFiles) {
|
||||
string[]@ files = find_files(basePath + "/*.ogg");
|
||||
void gather_pet_sound_files(const string& in basePath, string[] @outFiles) {
|
||||
string[] @files = find_files(basePath + "/*.ogg");
|
||||
if (@files !is null) {
|
||||
for (uint i = 0; i < files.length(); i++) {
|
||||
outFiles.insert_last(basePath + "/" + files[i]);
|
||||
}
|
||||
}
|
||||
|
||||
string[]@ folders = find_directories(basePath + "/*");
|
||||
string[] @folders = find_directories(basePath + "/*");
|
||||
if (@folders !is null) {
|
||||
for (uint i = 0; i < folders.length(); i++) {
|
||||
gather_pet_sound_files(basePath + "/" + folders[i], outFiles);
|
||||
@@ -91,22 +92,24 @@ void gather_pet_sound_files(const string&in basePath, string[]@ outFiles) {
|
||||
}
|
||||
}
|
||||
|
||||
bool sort_pet_sound_paths(const string &in a, const string &in b) {
|
||||
bool sort_pet_sound_paths(const string& in a, const string& in b) {
|
||||
return a.lower() < b.lower();
|
||||
}
|
||||
|
||||
void init_pet_sounds() {
|
||||
if (petSoundsInitialized) return;
|
||||
if (petSoundsInitialized)
|
||||
return;
|
||||
petSoundsInitialized = true;
|
||||
petSoundPaths.resize(0);
|
||||
if (!directory_exists("sounds/pets")) return;
|
||||
if (!directory_exists("sounds/pets"))
|
||||
return;
|
||||
gather_pet_sound_files("sounds/pets", petSoundPaths);
|
||||
if (petSoundPaths.length() > 1) {
|
||||
petSoundPaths.sort(sort_pet_sound_paths);
|
||||
}
|
||||
}
|
||||
|
||||
string get_pet_name_from_sound_path(const string&in soundPath) {
|
||||
string get_pet_name_from_sound_path(const string& in soundPath) {
|
||||
string normalizedPath = normalize_pet_path(soundPath);
|
||||
int slashPos = normalizedPath.find_last_of("/");
|
||||
string name = (slashPos >= 0) ? normalizedPath.substr(slashPos + 1) : normalizedPath;
|
||||
@@ -119,13 +122,15 @@ string get_pet_name_from_sound_path(const string&in soundPath) {
|
||||
name = collapse_pet_spaces(name);
|
||||
name = name.lower();
|
||||
name.trim_whitespace_this();
|
||||
if (name.length() == 0) return "Pet";
|
||||
if (name.length() == 0)
|
||||
return "Pet";
|
||||
string first = name.substr(0, 1).upper();
|
||||
if (name.length() == 1) return first;
|
||||
if (name.length() == 1)
|
||||
return first;
|
||||
return first + name.substr(1);
|
||||
}
|
||||
|
||||
string get_pet_sound_for_name(const string&in petName) {
|
||||
string get_pet_sound_for_name(const string& in petName) {
|
||||
init_pet_sounds();
|
||||
string target = petName.lower();
|
||||
for (uint i = 0; i < petSoundPaths.length(); i++) {
|
||||
@@ -144,17 +149,13 @@ string get_pet_sound_for_name(const string&in petName) {
|
||||
}
|
||||
|
||||
int get_pet_food_personal_total() {
|
||||
return get_personal_count(ITEM_MEAT)
|
||||
+ get_personal_count(ITEM_SMOKED_FISH)
|
||||
+ get_personal_count(ITEM_FISH)
|
||||
+ get_personal_count(ITEM_BASKET_FOOD);
|
||||
return get_personal_count(ITEM_MEAT) + get_personal_count(ITEM_SMOKED_FISH) + get_personal_count(ITEM_FISH) +
|
||||
get_personal_count(ITEM_BASKET_FOOD);
|
||||
}
|
||||
|
||||
int get_pet_food_storage_total() {
|
||||
return get_storage_count(ITEM_MEAT)
|
||||
+ get_storage_count(ITEM_SMOKED_FISH)
|
||||
+ get_storage_count(ITEM_FISH)
|
||||
+ get_storage_count(ITEM_BASKET_FOOD);
|
||||
return get_storage_count(ITEM_MEAT) + get_storage_count(ITEM_SMOKED_FISH) + get_storage_count(ITEM_FISH) +
|
||||
get_storage_count(ITEM_BASKET_FOOD);
|
||||
}
|
||||
|
||||
bool has_pet_food_available() {
|
||||
@@ -199,9 +200,11 @@ bool consume_pet_food() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void queue_pet_event(const string&in message, int soundPos = -1, bool playSound = true) {
|
||||
if (!petActive) return;
|
||||
if (message.length() == 0) return;
|
||||
void queue_pet_event(const string& in message, int soundPos = -1, bool playSound = true) {
|
||||
if (!petActive)
|
||||
return;
|
||||
if (message.length() == 0)
|
||||
return;
|
||||
petEventMessages.insert_last(message);
|
||||
if (playSound) {
|
||||
petEventSounds.insert_last(petSoundPath);
|
||||
@@ -213,12 +216,14 @@ void queue_pet_event(const string&in message, int soundPos = -1, bool playSound
|
||||
|
||||
string get_pet_display_name() {
|
||||
string name = normalize_pet_name_text(petType);
|
||||
if (name == "") return "pet";
|
||||
if (name == "")
|
||||
return "pet";
|
||||
return name;
|
||||
}
|
||||
|
||||
int get_pet_listener_pos() {
|
||||
if (petAdventurePlayerPos >= 0) return petAdventurePlayerPos;
|
||||
if (petAdventurePlayerPos >= 0)
|
||||
return petAdventurePlayerPos;
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -232,7 +237,8 @@ string get_health_report() {
|
||||
}
|
||||
|
||||
int get_pet_search_origin() {
|
||||
if (petOut && petPositionValid) return petPosition;
|
||||
if (petOut && petPositionValid)
|
||||
return petPosition;
|
||||
return get_pet_listener_pos();
|
||||
}
|
||||
|
||||
@@ -241,14 +247,16 @@ bool is_hawk_pet() {
|
||||
}
|
||||
|
||||
void play_pet_travel_step_sound(int stepPos) {
|
||||
if (stepPos < 0 || stepPos >= MAP_SIZE) return;
|
||||
if (stepPos < 0 || stepPos >= MAP_SIZE)
|
||||
return;
|
||||
|
||||
int listenerPos = get_pet_listener_pos();
|
||||
if (abs(stepPos - listenerPos) > CREATURE_DEFAULT_FOOTSTEP_DISTANCE) return;
|
||||
if (abs(stepPos - listenerPos) > CREATURE_DEFAULT_FOOTSTEP_DISTANCE)
|
||||
return;
|
||||
|
||||
if (is_hawk_pet()) {
|
||||
string flySoundPath = "sounds/terrain/fly.ogg";
|
||||
if (file_exists(flySoundPath)) {
|
||||
if (audio_asset_exists(flySoundPath)) {
|
||||
play_1d_with_volume_step(flySoundPath, listenerPos, stepPos, false, CREATURE_DEFAULT_VOLUME_STEP);
|
||||
return;
|
||||
}
|
||||
@@ -264,13 +272,15 @@ void update_pet_travel_position(int currentPos) {
|
||||
petPositionValid = true;
|
||||
previousPos = petPosition;
|
||||
}
|
||||
if (currentPos == previousPos) return;
|
||||
if (currentPos == previousPos)
|
||||
return;
|
||||
|
||||
int stepDir = (currentPos > previousPos) ? 1 : -1;
|
||||
int stepPos = previousPos + stepDir;
|
||||
while (true) {
|
||||
play_pet_travel_step_sound(stepPos);
|
||||
if (stepPos == currentPos) break;
|
||||
if (stepPos == currentPos)
|
||||
break;
|
||||
stepPos += stepDir;
|
||||
}
|
||||
petPosition = currentPos;
|
||||
@@ -280,7 +290,8 @@ bool is_pet_knocked_out() {
|
||||
return petKnockoutHoursRemaining > 0 || petHealth <= 0;
|
||||
}
|
||||
|
||||
void begin_pet_adventure(PetAdventureFindTargetCallback@ findTarget, PetAdventureDamageCallback@ damageTarget, int playerPos) {
|
||||
void begin_pet_adventure(PetAdventureFindTargetCallback @findTarget, PetAdventureDamageCallback @damageTarget,
|
||||
int playerPos) {
|
||||
petAdventureMode = true;
|
||||
petAdventurePlayerPos = playerPos;
|
||||
petAdventurePreOut = petOut;
|
||||
@@ -320,7 +331,8 @@ void end_pet_adventure() {
|
||||
}
|
||||
|
||||
void queue_pet_return_event() {
|
||||
if (!petActive) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
queue_pet_event("A " + get_pet_display_name() + " returns to you.");
|
||||
}
|
||||
|
||||
@@ -329,12 +341,14 @@ bool is_pet_at_player_position() {
|
||||
}
|
||||
|
||||
bool is_pet_within_follow_distance() {
|
||||
if (!petPositionValid) return false;
|
||||
if (!petPositionValid)
|
||||
return false;
|
||||
return abs(petPosition - get_pet_listener_pos()) <= PET_FOLLOW_MAX_DISTANCE;
|
||||
}
|
||||
|
||||
bool is_pet_within_follow_comfort_distance() {
|
||||
if (!petPositionValid) return false;
|
||||
if (!petPositionValid)
|
||||
return false;
|
||||
return abs(petPosition - get_pet_listener_pos()) <= PET_FOLLOW_COMFORT_DISTANCE;
|
||||
}
|
||||
|
||||
@@ -347,7 +361,8 @@ void complete_pet_return() {
|
||||
}
|
||||
|
||||
void knock_out_pet() {
|
||||
if (!petActive) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
petHealth = 0;
|
||||
petKnockoutHoursRemaining = PET_KNOCKOUT_COOLDOWN_HOURS;
|
||||
petOut = false;
|
||||
@@ -377,9 +392,10 @@ void update_pet_events() {
|
||||
|
||||
string soundPath = petEventSounds[0];
|
||||
int soundPos = petEventPositions[0];
|
||||
if (soundPath != "" && file_exists(soundPath)) {
|
||||
if (soundPath != "" && audio_asset_exists(soundPath)) {
|
||||
if (soundPos >= 0) {
|
||||
petEventSoundHandle = play_1d_with_volume_step(soundPath, get_pet_listener_pos(), soundPos, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
petEventSoundHandle = play_1d_with_volume_step(soundPath, get_pet_listener_pos(), soundPos, false,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
} else {
|
||||
petEventSoundHandle = p.play_stationary(soundPath, false);
|
||||
}
|
||||
@@ -432,10 +448,12 @@ void reset_pet_state() {
|
||||
}
|
||||
|
||||
void pet_leave() {
|
||||
if (!petActive) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
|
||||
string oldPet = normalize_pet_name_text(petType);
|
||||
if (oldPet == "") oldPet = "pet";
|
||||
if (oldPet == "")
|
||||
oldPet = "pet";
|
||||
speak_with_history(oldPet + " leaves.", true);
|
||||
|
||||
if (!petOut) {
|
||||
@@ -449,6 +467,28 @@ void pet_leave() {
|
||||
stop_pet_travel();
|
||||
}
|
||||
|
||||
bool abandon_pet() {
|
||||
if (!petActive)
|
||||
return false;
|
||||
|
||||
if (is_pet_knocked_out()) {
|
||||
speak_with_history("Your " + get_pet_display_name() + " is unconscious. You can't abandon it right now.", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Force the pet out first so leaving uses travel-out behavior instead of instant reset.
|
||||
if (!petOut) {
|
||||
petOut = true;
|
||||
petRecallRequested = false;
|
||||
petPosition = get_pet_listener_pos();
|
||||
petPositionValid = true;
|
||||
}
|
||||
|
||||
petLoyalty = 0;
|
||||
pet_leave();
|
||||
return true;
|
||||
}
|
||||
|
||||
void start_pet_travel_leave() {
|
||||
stop_pet_travel();
|
||||
petTravelActive = true;
|
||||
@@ -469,24 +509,22 @@ void start_pet_travel_leave() {
|
||||
petTravelDurationMs = get_pet_travel_duration_ms(petTravelStartPos, petTravelTargetPos, true);
|
||||
petTravelTimer.restart();
|
||||
|
||||
if (petSoundPath != "" && file_exists(petSoundPath)) {
|
||||
petTravelSoundHandle = play_1d_with_volume_step(
|
||||
petSoundPath,
|
||||
get_pet_listener_pos(),
|
||||
petTravelStartPos,
|
||||
true,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP
|
||||
);
|
||||
if (petSoundPath != "" && audio_asset_exists(petSoundPath)) {
|
||||
petTravelSoundHandle = play_1d_with_volume_step(petSoundPath, get_pet_listener_pos(), petTravelStartPos, true,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
void clamp_pet_loyalty() {
|
||||
if (petLoyalty < 0) petLoyalty = 0;
|
||||
if (petLoyalty > PET_LOYALTY_MAX) petLoyalty = PET_LOYALTY_MAX;
|
||||
if (petLoyalty < 0)
|
||||
petLoyalty = 0;
|
||||
if (petLoyalty > PET_LOYALTY_MAX)
|
||||
petLoyalty = PET_LOYALTY_MAX;
|
||||
}
|
||||
|
||||
void adjust_pet_loyalty(int delta) {
|
||||
if (!petActive) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
petLoyalty += delta;
|
||||
clamp_pet_loyalty();
|
||||
if (petLoyalty <= 0) {
|
||||
@@ -495,10 +533,12 @@ void adjust_pet_loyalty(int delta) {
|
||||
}
|
||||
|
||||
void check_pet_call_key() {
|
||||
if (!key_pressed(KEY_SPACE)) return;
|
||||
if (!key_pressed(KEY_SPACE))
|
||||
return;
|
||||
if (petLeaving) {
|
||||
string name = petLeavingName;
|
||||
if (name == "") name = "pet";
|
||||
if (name == "")
|
||||
name = "pet";
|
||||
speak_with_history("Your " + name + " is leaving.", true);
|
||||
return;
|
||||
}
|
||||
@@ -527,19 +567,20 @@ void check_pet_call_key() {
|
||||
return;
|
||||
}
|
||||
adjust_pet_loyalty(-PET_LOYALTY_CALLOUT_COST);
|
||||
if (!petActive) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
petOut = true;
|
||||
petRecallRequested = false;
|
||||
petPosition = get_pet_listener_pos();
|
||||
petPositionValid = true;
|
||||
if (file_exists("sounds/actions/call_pet.ogg")) {
|
||||
if (audio_asset_exists("sounds/actions/call_pet.ogg")) {
|
||||
/* But I can feel it, black water washes over me.
|
||||
As it soothes I call to you with my control. */
|
||||
p.play_stationary("sounds/actions/call_pet.ogg", false);
|
||||
}
|
||||
}
|
||||
|
||||
void adopt_pet(const string&in soundPath) {
|
||||
void adopt_pet(const string& in soundPath) {
|
||||
petActive = true;
|
||||
petSoundPath = soundPath;
|
||||
petType = get_pet_name_from_sound_path(soundPath);
|
||||
@@ -575,15 +616,17 @@ int get_pet_travel_duration_ms(int startPos, int targetPos, bool chargeTravel =
|
||||
int speedPerTile = walk_speed;
|
||||
if (chargeTravel) {
|
||||
speedPerTile = int(float(walk_speed) / PET_CHARGE_SPEED_MULTIPLIER);
|
||||
if (speedPerTile < 1) speedPerTile = 1;
|
||||
if (speedPerTile < 1)
|
||||
speedPerTile = 1;
|
||||
}
|
||||
|
||||
int duration = distance * speedPerTile;
|
||||
if (duration < PET_TRAVEL_MIN_MS) duration = PET_TRAVEL_MIN_MS;
|
||||
if (duration < PET_TRAVEL_MIN_MS)
|
||||
duration = PET_TRAVEL_MIN_MS;
|
||||
return duration;
|
||||
}
|
||||
|
||||
void start_pet_travel_attack(int targetPos, const string&in targetLabel, int targetKind) {
|
||||
void start_pet_travel_attack(int targetPos, const string& in targetLabel, int targetKind) {
|
||||
stop_pet_travel();
|
||||
petTravelActive = true;
|
||||
petTravelAction = PET_TRAVEL_ATTACK;
|
||||
@@ -596,14 +639,9 @@ void start_pet_travel_attack(int targetPos, const string&in targetLabel, int tar
|
||||
petTravelDurationMs = get_pet_travel_duration_ms(petTravelStartPos, targetPos, true);
|
||||
petTravelTimer.restart();
|
||||
|
||||
if (petSoundPath != "" && file_exists(petSoundPath)) {
|
||||
petTravelSoundHandle = play_1d_with_volume_step(
|
||||
petSoundPath,
|
||||
get_pet_listener_pos(),
|
||||
petTravelStartPos,
|
||||
true,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP
|
||||
);
|
||||
if (petSoundPath != "" && audio_asset_exists(petSoundPath)) {
|
||||
petTravelSoundHandle = play_1d_with_volume_step(petSoundPath, get_pet_listener_pos(), petTravelStartPos, true,
|
||||
PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,8 +670,10 @@ void start_pet_travel_return(int targetPos) {
|
||||
}
|
||||
|
||||
void request_pet_return() {
|
||||
if (petLeaving) return;
|
||||
if (!petActive || !petOut) return;
|
||||
if (petLeaving)
|
||||
return;
|
||||
if (!petActive || !petOut)
|
||||
return;
|
||||
if (!petPositionValid) {
|
||||
petPosition = get_pet_listener_pos();
|
||||
petPositionValid = true;
|
||||
@@ -646,8 +686,10 @@ void request_pet_return() {
|
||||
}
|
||||
|
||||
void request_pet_follow() {
|
||||
if (petLeaving) return;
|
||||
if (!petActive || !petOut) return;
|
||||
if (petLeaving)
|
||||
return;
|
||||
if (!petActive || !petOut)
|
||||
return;
|
||||
petRecallRequested = false;
|
||||
if (!petPositionValid) {
|
||||
petPosition = get_pet_listener_pos();
|
||||
@@ -661,8 +703,10 @@ void request_pet_follow() {
|
||||
}
|
||||
|
||||
void play_pet_recall_ack() {
|
||||
if (!petActive) return;
|
||||
if (petSoundPath == "" || !file_exists(petSoundPath)) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
if (petSoundPath == "" || !audio_asset_exists(petSoundPath))
|
||||
return;
|
||||
int listenerPos = get_pet_listener_pos();
|
||||
if (petPositionValid) {
|
||||
play_1d_with_volume_step(petSoundPath, listenerPos, petPosition, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
|
||||
@@ -672,8 +716,10 @@ void play_pet_recall_ack() {
|
||||
}
|
||||
|
||||
void update_pet_travel() {
|
||||
if (!petTravelActive) return;
|
||||
if (petTravelDurationMs < 1) petTravelDurationMs = 1;
|
||||
if (!petTravelActive)
|
||||
return;
|
||||
if (petTravelDurationMs < 1)
|
||||
petTravelDurationMs = 1;
|
||||
|
||||
if (petTravelAction == PET_TRAVEL_RETURN) {
|
||||
if (!petPositionValid) {
|
||||
@@ -697,9 +743,11 @@ void update_pet_travel() {
|
||||
int stepInterval = walk_speed;
|
||||
if (distanceToPlayer > PET_FOLLOW_MAX_DISTANCE) {
|
||||
stepInterval = int(float(walk_speed) / PET_CHARGE_SPEED_MULTIPLIER);
|
||||
if (stepInterval < 1) stepInterval = 1;
|
||||
if (stepInterval < 1)
|
||||
stepInterval = 1;
|
||||
}
|
||||
if (stepInterval < PET_TRAVEL_MIN_MS) stepInterval = PET_TRAVEL_MIN_MS;
|
||||
if (stepInterval < PET_TRAVEL_MIN_MS)
|
||||
stepInterval = PET_TRAVEL_MIN_MS;
|
||||
|
||||
if (petTravelTimer.elapsed < stepInterval) {
|
||||
return;
|
||||
@@ -734,7 +782,8 @@ void update_pet_travel() {
|
||||
|
||||
int elapsed = petTravelTimer.elapsed;
|
||||
float progress = float(elapsed) / float(petTravelDurationMs);
|
||||
if (progress > 1.0f) progress = 1.0f;
|
||||
if (progress > 1.0f)
|
||||
progress = 1.0f;
|
||||
|
||||
int travel = int(float(petTravelTargetPos - petTravelStartPos) * progress);
|
||||
int currentPos = petTravelStartPos + travel;
|
||||
@@ -743,7 +792,14 @@ void update_pet_travel() {
|
||||
p.update_sound_1d(petTravelSoundHandle, currentPos);
|
||||
}
|
||||
|
||||
if (elapsed < petTravelDurationMs) return;
|
||||
if (petTravelAction == PET_TRAVEL_LEAVE &&
|
||||
abs(currentPos - get_pet_listener_pos()) >= PET_LEAVE_DESPAWN_DISTANCE) {
|
||||
reset_pet_state();
|
||||
return;
|
||||
}
|
||||
|
||||
if (elapsed < petTravelDurationMs)
|
||||
return;
|
||||
|
||||
safe_destroy_sound(petTravelSoundHandle);
|
||||
petTravelSoundHandle = -1;
|
||||
@@ -776,7 +832,7 @@ void update_pet_travel() {
|
||||
int nextTargetKind = -1;
|
||||
bool hasNextTarget = find_pet_attack_target(nextTargetPos, nextTargetLabel, nextTargetKind);
|
||||
if (!hasNextTarget) {
|
||||
WorldDrop@ drop = find_pet_drop_target();
|
||||
WorldDrop @drop = find_pet_drop_target();
|
||||
if (drop !is null) {
|
||||
petRetrieveTimer.restart();
|
||||
start_pet_travel_retrieve(drop.position);
|
||||
@@ -785,7 +841,7 @@ void update_pet_travel() {
|
||||
request_pet_follow();
|
||||
}
|
||||
} else if (petTravelAction == PET_TRAVEL_RETRIEVE) {
|
||||
WorldDrop@ drop = get_drop_at(petTravelTargetPos);
|
||||
WorldDrop @drop = get_drop_at(petTravelTargetPos);
|
||||
if (drop !is null) {
|
||||
string message = "";
|
||||
if (try_pet_pickup_world_drop(drop, message)) {
|
||||
@@ -793,7 +849,7 @@ void update_pet_travel() {
|
||||
queue_pet_event(message, -1, false);
|
||||
petPosition = petTravelTargetPos;
|
||||
petPositionValid = true;
|
||||
WorldDrop@ nextDrop = find_pet_drop_target();
|
||||
WorldDrop @nextDrop = find_pet_drop_target();
|
||||
if (nextDrop !is null) {
|
||||
petRetrieveTimer.restart();
|
||||
start_pet_travel_retrieve(nextDrop.position);
|
||||
@@ -818,10 +874,13 @@ void update_pet_travel() {
|
||||
stop_pet_travel();
|
||||
}
|
||||
|
||||
bool run_pet_offer_menu(const string&in soundPath, const string&in reasonText) {
|
||||
if (petActive) return false;
|
||||
if (soundPath == "" || !file_exists(soundPath)) return false;
|
||||
if (!has_pet_food_available()) return false;
|
||||
bool run_pet_offer_menu(const string& in soundPath, const string& in reasonText) {
|
||||
if (petActive)
|
||||
return false;
|
||||
if (soundPath == "" || !audio_asset_exists(soundPath))
|
||||
return false;
|
||||
if (!has_pet_food_available())
|
||||
return false;
|
||||
|
||||
string petName = get_pet_name_from_sound_path(soundPath);
|
||||
string prompt = "A friendly looking " + petName + " begs for food. Accept?";
|
||||
@@ -848,13 +907,15 @@ bool run_pet_offer_menu(const string&in soundPath, const string&in reasonText) {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(options.length())) selection = 0;
|
||||
if (selection >= int(options.length()))
|
||||
selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = int(options.length()) - 1;
|
||||
if (selection < 0)
|
||||
selection = int(options.length()) - 1;
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
@@ -870,35 +931,44 @@ bool run_pet_offer_menu(const string&in soundPath, const string&in reasonText) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void attempt_pet_offer_random(const string&in reasonText) {
|
||||
if (petActive) return;
|
||||
if (!has_pet_food_available()) return;
|
||||
void attempt_pet_offer_random(const string& in reasonText) {
|
||||
if (petActive)
|
||||
return;
|
||||
if (!has_pet_food_available())
|
||||
return;
|
||||
init_pet_sounds();
|
||||
if (petSoundPaths.length() == 0) return;
|
||||
if (petSoundPaths.length() == 0)
|
||||
return;
|
||||
int pick = random(0, petSoundPaths.length() - 1);
|
||||
run_pet_offer_menu(petSoundPaths[pick], reasonText);
|
||||
}
|
||||
|
||||
void attempt_pet_offer_from_quest(int score) {
|
||||
if (score < QUEST_LOG_SCORE) return;
|
||||
if (score < QUEST_LOG_SCORE)
|
||||
return;
|
||||
attempt_pet_offer_random("");
|
||||
}
|
||||
|
||||
void attempt_pet_offer_from_adventure() {
|
||||
if (petActive) return;
|
||||
if (random(1, 100) > PET_ADVENTURE_CHANCE) return;
|
||||
if (petActive)
|
||||
return;
|
||||
if (random(1, 100) > PET_ADVENTURE_CHANCE)
|
||||
return;
|
||||
attempt_pet_offer_random("");
|
||||
}
|
||||
|
||||
void attempt_pet_offer_from_tree() {
|
||||
if (petActive) return;
|
||||
if (random(1, 100) > PET_TREE_HAWK_CHANCE) return;
|
||||
if (petActive)
|
||||
return;
|
||||
if (random(1, 100) > PET_TREE_HAWK_CHANCE)
|
||||
return;
|
||||
string hawkSound = get_pet_sound_for_name("hawk");
|
||||
if (hawkSound == "") return;
|
||||
if (hawkSound == "")
|
||||
return;
|
||||
run_pet_offer_menu(hawkSound, "");
|
||||
}
|
||||
|
||||
bool try_pet_pickup_small_game(const string&in gameType, string &out message) {
|
||||
bool try_pet_pickup_small_game(const string& in gameType, string& out message) {
|
||||
if (get_personal_count(ITEM_SMALL_GAME) >= get_personal_stack_limit()) {
|
||||
message = "You can't carry a " + gameType + ", so you give it to a " + get_pet_display_name() + " to chew on.";
|
||||
return true;
|
||||
@@ -909,8 +979,9 @@ bool try_pet_pickup_small_game(const string&in gameType, string &out message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_pet_pickup_world_drop(WorldDrop@ drop, string &out message) {
|
||||
if (drop is null) return false;
|
||||
bool try_pet_pickup_world_drop(WorldDrop @drop, string& out message) {
|
||||
if (drop is null)
|
||||
return false;
|
||||
if (get_flying_creature_config_by_drop_type(drop.type) !is null) {
|
||||
return try_pet_pickup_small_game(drop.type, message);
|
||||
}
|
||||
@@ -940,13 +1011,14 @@ bool try_pet_pickup_world_drop(WorldDrop@ drop, string &out message) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldDrop@ find_pet_drop_target() {
|
||||
WorldDrop @find_pet_drop_target() {
|
||||
int bestDistance = PET_RANGE + 1;
|
||||
WorldDrop@ best = null;
|
||||
WorldDrop @best = null;
|
||||
int origin = get_pet_search_origin();
|
||||
for (uint i = 0; i < world_drops.length(); i++) {
|
||||
int distance = abs(world_drops[i].position - origin);
|
||||
if (distance > PET_RANGE) continue;
|
||||
if (distance > PET_RANGE)
|
||||
continue;
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
@best = world_drops[i];
|
||||
@@ -956,23 +1028,32 @@ WorldDrop@ find_pet_drop_target() {
|
||||
}
|
||||
|
||||
void update_pet_retrieval() {
|
||||
if (!petActive) return;
|
||||
if (!petOut) return;
|
||||
if (petLoyalty <= 0) return;
|
||||
if (petAdventureMode) return;
|
||||
if (is_pet_knocked_out()) return;
|
||||
if (petRetrieveTimer.elapsed < PET_RETRIEVE_COOLDOWN) return;
|
||||
if (petEventMessages.length() > 2) return;
|
||||
if (petTravelActive) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
if (!petOut)
|
||||
return;
|
||||
if (petLoyalty <= 0)
|
||||
return;
|
||||
if (petAdventureMode)
|
||||
return;
|
||||
if (is_pet_knocked_out())
|
||||
return;
|
||||
if (petRetrieveTimer.elapsed < PET_RETRIEVE_COOLDOWN)
|
||||
return;
|
||||
if (petEventMessages.length() > 2)
|
||||
return;
|
||||
if (petTravelActive)
|
||||
return;
|
||||
|
||||
WorldDrop@ drop = find_pet_drop_target();
|
||||
if (drop is null) return;
|
||||
WorldDrop @drop = find_pet_drop_target();
|
||||
if (drop is null)
|
||||
return;
|
||||
|
||||
petRetrieveTimer.restart();
|
||||
start_pet_travel_retrieve(drop.position);
|
||||
}
|
||||
|
||||
bool find_pet_attack_target(int &out targetPos, string &out targetLabel, int &out targetKind) {
|
||||
bool find_pet_attack_target(int& out targetPos, string& out targetLabel, int& out targetKind) {
|
||||
int bestDistance = PET_RANGE + 1;
|
||||
targetPos = -1;
|
||||
targetLabel = "";
|
||||
@@ -984,7 +1065,8 @@ bool find_pet_attack_target(int &out targetPos, string &out targetLabel, int &ou
|
||||
|
||||
for (uint i = 0; i < bandits.length(); i++) {
|
||||
int distance = abs(bandits[i].position - origin);
|
||||
if (distance > PET_RANGE) continue;
|
||||
if (distance > PET_RANGE)
|
||||
continue;
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
targetPos = bandits[i].position;
|
||||
@@ -994,9 +1076,11 @@ bool find_pet_attack_target(int &out targetPos, string &out targetLabel, int &ou
|
||||
}
|
||||
|
||||
for (uint i = 0; i < undeads.length(); i++) {
|
||||
if (undeads[i].undead_type == "undead_resident") continue;
|
||||
if (undeads[i].undead_type == "undead_resident")
|
||||
continue;
|
||||
int distance = abs(undeads[i].position - origin);
|
||||
if (distance > PET_RANGE) continue;
|
||||
if (distance > PET_RANGE)
|
||||
continue;
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
targetPos = undeads[i].position;
|
||||
@@ -1007,7 +1091,8 @@ bool find_pet_attack_target(int &out targetPos, string &out targetLabel, int &ou
|
||||
|
||||
for (uint i = 0; i < ground_games.length(); i++) {
|
||||
int distance = abs(ground_games[i].position - origin);
|
||||
if (distance > PET_RANGE) continue;
|
||||
if (distance > PET_RANGE)
|
||||
continue;
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
targetPos = ground_games[i].position;
|
||||
@@ -1019,7 +1104,7 @@ bool find_pet_attack_target(int &out targetPos, string &out targetLabel, int &ou
|
||||
return targetPos != -1;
|
||||
}
|
||||
|
||||
bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int &out targetPos) {
|
||||
bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int& out targetPos) {
|
||||
int bestDistance = PET_RANGE + 1;
|
||||
targetPos = -1;
|
||||
int origin = get_pet_search_origin();
|
||||
@@ -1032,7 +1117,8 @@ bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int &out t
|
||||
if (targetKind == 0) {
|
||||
for (uint i = 0; i < bandits.length(); i++) {
|
||||
int distanceToOrigin = abs(bandits[i].position - origin);
|
||||
if (distanceToOrigin > PET_RANGE) continue;
|
||||
if (distanceToOrigin > PET_RANGE)
|
||||
continue;
|
||||
int distance = abs(bandits[i].position - referencePos);
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
@@ -1041,9 +1127,11 @@ bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int &out t
|
||||
}
|
||||
} else if (targetKind == 1) {
|
||||
for (uint i = 0; i < undeads.length(); i++) {
|
||||
if (undeads[i].undead_type == "undead_resident") continue;
|
||||
if (undeads[i].undead_type == "undead_resident")
|
||||
continue;
|
||||
int distanceToOrigin = abs(undeads[i].position - origin);
|
||||
if (distanceToOrigin > PET_RANGE) continue;
|
||||
if (distanceToOrigin > PET_RANGE)
|
||||
continue;
|
||||
int distance = abs(undeads[i].position - referencePos);
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
@@ -1053,7 +1141,8 @@ bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int &out t
|
||||
} else if (targetKind == 2) {
|
||||
for (uint i = 0; i < ground_games.length(); i++) {
|
||||
int distanceToOrigin = abs(ground_games[i].position - origin);
|
||||
if (distanceToOrigin > PET_RANGE) continue;
|
||||
if (distanceToOrigin > PET_RANGE)
|
||||
continue;
|
||||
int distance = abs(ground_games[i].position - referencePos);
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
@@ -1066,61 +1155,84 @@ bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int &out t
|
||||
}
|
||||
|
||||
void update_pet_attack() {
|
||||
if (!petActive) return;
|
||||
if (!petOut) return;
|
||||
if (petLoyalty <= 0) return;
|
||||
if (is_pet_knocked_out()) return;
|
||||
if (petAttackTimer.elapsed < PET_ATTACK_COOLDOWN) return;
|
||||
if (petTravelActive) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
if (!petOut)
|
||||
return;
|
||||
if (petLoyalty <= 0)
|
||||
return;
|
||||
if (is_pet_knocked_out())
|
||||
return;
|
||||
if (petAttackTimer.elapsed < PET_ATTACK_COOLDOWN)
|
||||
return;
|
||||
if (petTravelActive)
|
||||
return;
|
||||
|
||||
int targetPos = -1;
|
||||
string targetLabel = "";
|
||||
int targetKind = -1;
|
||||
if (!find_pet_attack_target(targetPos, targetLabel, targetKind)) return;
|
||||
if (!find_pet_attack_target(targetPos, targetLabel, targetKind))
|
||||
return;
|
||||
|
||||
petAttackTimer.restart();
|
||||
start_pet_travel_attack(targetPos, targetLabel, targetKind);
|
||||
}
|
||||
|
||||
void update_pet_follow() {
|
||||
if (!petActive) return;
|
||||
if (!petOut) return;
|
||||
if (petAdventureMode) return;
|
||||
if (is_pet_knocked_out()) return;
|
||||
if (petTravelActive) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
if (!petOut)
|
||||
return;
|
||||
if (petAdventureMode)
|
||||
return;
|
||||
if (is_pet_knocked_out())
|
||||
return;
|
||||
if (petTravelActive)
|
||||
return;
|
||||
|
||||
WorldDrop@ drop = find_pet_drop_target();
|
||||
if (drop !is null) return;
|
||||
WorldDrop @drop = find_pet_drop_target();
|
||||
if (drop !is null)
|
||||
return;
|
||||
|
||||
int targetPos = -1;
|
||||
string targetLabel = "";
|
||||
int targetKind = -1;
|
||||
if (find_pet_attack_target(targetPos, targetLabel, targetKind)) return;
|
||||
if (find_pet_attack_target(targetPos, targetLabel, targetKind))
|
||||
return;
|
||||
|
||||
if (is_pet_within_follow_comfort_distance()) return;
|
||||
if (is_pet_within_follow_comfort_distance())
|
||||
return;
|
||||
request_pet_follow();
|
||||
}
|
||||
|
||||
void attempt_pet_random_find() {
|
||||
if (!petActive) return;
|
||||
if (!petOut) return;
|
||||
if (petLoyalty < PET_LOYALTY_BONUS_THRESHOLD) return;
|
||||
if (random(1, 100) > PET_RANDOM_FIND_CHANCE) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
if (!petOut)
|
||||
return;
|
||||
if (petLoyalty < PET_LOYALTY_BONUS_THRESHOLD)
|
||||
return;
|
||||
if (random(1, 100) > PET_RANDOM_FIND_CHANCE)
|
||||
return;
|
||||
|
||||
int[] possibleItems = {ITEM_STICKS, ITEM_VINES, ITEM_STONES, ITEM_CLAY};
|
||||
int itemType = possibleItems[random(0, possibleItems.length() - 1)];
|
||||
int added = add_to_stack(get_personal_count(itemType), 1);
|
||||
if (added <= 0) return;
|
||||
if (added <= 0)
|
||||
return;
|
||||
|
||||
add_personal_count(itemType, added);
|
||||
string itemName = (added == 1) ? item_registry[itemType].singular : item_registry[itemType].name;
|
||||
queue_pet_event("Your " + get_pet_display_name() + " retrieved " + added + " " + itemName + ".", petPositionValid ? petPosition : x, false);
|
||||
queue_pet_event("Your " + get_pet_display_name() + " retrieved " + added + " " + itemName + ".",
|
||||
petPositionValid ? petPosition : x, false);
|
||||
request_pet_follow();
|
||||
}
|
||||
|
||||
void handle_pet_hourly_update(int hour) {
|
||||
if (!petActive) return;
|
||||
if (petLeaving) return;
|
||||
if (!petActive)
|
||||
return;
|
||||
if (petLeaving)
|
||||
return;
|
||||
|
||||
if (petKnockoutHoursRemaining > 0) {
|
||||
petKnockoutHoursRemaining--;
|
||||
@@ -1133,12 +1245,14 @@ void handle_pet_hourly_update(int hour) {
|
||||
|
||||
if (petKnockoutHoursRemaining <= 0 && !petOut && petHealth > 0 && petHealth < PET_HEALTH_MAX) {
|
||||
petHealth += 1;
|
||||
if (petHealth > PET_HEALTH_MAX) petHealth = PET_HEALTH_MAX;
|
||||
if (petHealth > PET_HEALTH_MAX)
|
||||
petHealth = PET_HEALTH_MAX;
|
||||
}
|
||||
|
||||
if (petOut) {
|
||||
adjust_pet_loyalty(-1);
|
||||
if (!petActive || petLeaving) return;
|
||||
if (!petActive || petLeaving)
|
||||
return;
|
||||
if (petLoyalty <= 1 && !petHungryWarned) {
|
||||
notify("A " + get_pet_display_name() + " is getting hungry.");
|
||||
petHungryWarned = true;
|
||||
|
||||
+64
-36
@@ -16,11 +16,16 @@ int[] quest_queue;
|
||||
bool quest_roll_done_today = false;
|
||||
|
||||
string get_quest_name(int quest_type) {
|
||||
if (quest_type == QUEST_BAT_INVASION) return "Bat Invasion";
|
||||
if (quest_type == QUEST_CATCH_BOOMERANG) return "Catch the Boomerang";
|
||||
if (quest_type == QUEST_ENCHANTED_MELODY) return "Enchanted Melody";
|
||||
if (quest_type == QUEST_ESCAPE_FROM_HEL) return "Escape from Hel";
|
||||
if (quest_type == QUEST_SKELETAL_BARD) return "Skeletal Bard";
|
||||
if (quest_type == QUEST_BAT_INVASION)
|
||||
return "Bat Invasion";
|
||||
if (quest_type == QUEST_CATCH_BOOMERANG)
|
||||
return "Catch the Boomerang";
|
||||
if (quest_type == QUEST_ENCHANTED_MELODY)
|
||||
return "Enchanted Melody";
|
||||
if (quest_type == QUEST_ESCAPE_FROM_HEL)
|
||||
return "Escape from Hel";
|
||||
if (quest_type == QUEST_SKELETAL_BARD)
|
||||
return "Skeletal Bard";
|
||||
return "Unknown Quest";
|
||||
}
|
||||
|
||||
@@ -45,8 +50,10 @@ string get_quest_description(int quest_type) {
|
||||
|
||||
int get_quest_chance_from_favor() {
|
||||
int chance = int(favor * QUEST_CHANCE_PER_FAVOR);
|
||||
if (chance < QUEST_MIN_CHANCE && favor >= 1.0) chance = QUEST_MIN_CHANCE;
|
||||
if (chance > 100) chance = 100;
|
||||
if (chance < QUEST_MIN_CHANCE && favor >= 1.0)
|
||||
chance = QUEST_MIN_CHANCE;
|
||||
if (chance > 100)
|
||||
chance = 100;
|
||||
return chance;
|
||||
}
|
||||
|
||||
@@ -59,21 +66,27 @@ void quest_boomerang_hit_sound() {
|
||||
}
|
||||
|
||||
void add_quest(int quest_type) {
|
||||
if (quest_queue.length() >= QUEST_MAX_ACTIVE) return;
|
||||
if (quest_queue.length() >= QUEST_MAX_ACTIVE)
|
||||
return;
|
||||
quest_queue.insert_last(quest_type);
|
||||
notify("A new quest is available: " + get_quest_name(quest_type) + ".");
|
||||
}
|
||||
|
||||
void attempt_daily_quest() {
|
||||
if (quest_roll_done_today) return;
|
||||
if (favor < 1.0) return;
|
||||
if (world_altars.length() == 0) return;
|
||||
if (quest_queue.length() >= QUEST_MAX_ACTIVE) return;
|
||||
if (quest_roll_done_today)
|
||||
return;
|
||||
if (favor < 1.0)
|
||||
return;
|
||||
if (world_altars.length() == 0)
|
||||
return;
|
||||
if (quest_queue.length() >= QUEST_MAX_ACTIVE)
|
||||
return;
|
||||
|
||||
quest_roll_done_today = true;
|
||||
int chance = get_quest_chance_from_favor();
|
||||
int roll = random(1, 100);
|
||||
if (roll > chance) return;
|
||||
if (roll > chance)
|
||||
return;
|
||||
|
||||
int quest_type = random(0, QUEST_TYPE_COUNT - 1);
|
||||
add_quest(quest_type);
|
||||
@@ -94,18 +107,24 @@ void check_quest_menu() {
|
||||
}
|
||||
|
||||
string get_quest_favor_phrase(int score) {
|
||||
if (score <= 2) return "The gods are displeased with your performance.";
|
||||
if (score < QUEST_STONE_SCORE) return "The gods are pleased with your performance.";
|
||||
if (score <= 2)
|
||||
return "The gods are displeased with your performance.";
|
||||
if (score < QUEST_STONE_SCORE)
|
||||
return "The gods are pleased with your performance.";
|
||||
int extreme_threshold = QUEST_LOG_SCORE - 2;
|
||||
if (score < extreme_threshold) return "The gods are very pleased with your performance.";
|
||||
if (score < QUEST_LOG_SCORE) return "The gods are extremely pleased with your performance.";
|
||||
if (score < extreme_threshold)
|
||||
return "The gods are very pleased with your performance.";
|
||||
if (score < QUEST_LOG_SCORE)
|
||||
return "The gods are extremely pleased with your performance.";
|
||||
return "The gods are ultimately pleased with your performance.";
|
||||
}
|
||||
|
||||
void apply_quest_reward(int score) {
|
||||
double favor_gain = score * QUEST_FAVOR_PER_POINT;
|
||||
if (favor_gain < 0) favor_gain = 0;
|
||||
if (favor_gain > 1.0) favor_gain = 1.0;
|
||||
if (favor_gain < 0)
|
||||
favor_gain = 0;
|
||||
if (favor_gain > 1.0)
|
||||
favor_gain = 1.0;
|
||||
favor += favor_gain;
|
||||
|
||||
// Determine quantity based on score
|
||||
@@ -115,17 +134,19 @@ void apply_quest_reward(int score) {
|
||||
// 8-9: 3
|
||||
// >= 10: 4
|
||||
int quantity = 0;
|
||||
if (score >= QUEST_LOG_SCORE) quantity = 4;
|
||||
else if (score >= QUEST_LOG_SCORE - 2) quantity = 3;
|
||||
else if (score >= QUEST_STONE_SCORE) quantity = 2;
|
||||
else if (score > 2) quantity = 1;
|
||||
if (score >= QUEST_LOG_SCORE)
|
||||
quantity = 4;
|
||||
else if (score >= QUEST_LOG_SCORE - 2)
|
||||
quantity = 3;
|
||||
else if (score >= QUEST_STONE_SCORE)
|
||||
quantity = 2;
|
||||
else if (score > 2)
|
||||
quantity = 1;
|
||||
|
||||
// Select reward item
|
||||
int[] possible_rewards = {
|
||||
ITEM_STICKS, ITEM_VINES, ITEM_REEDS, ITEM_STONES, ITEM_LOGS, ITEM_CLAY,
|
||||
ITEM_MEAT, ITEM_SKINS, ITEM_FEATHERS, ITEM_DOWN, ITEM_FISH, ITEM_SMOKED_FISH,
|
||||
ITEM_HEAL_SCROLL, ITEM_INCENSE, ITEM_BASKET_FOOD
|
||||
};
|
||||
int[] possible_rewards = {ITEM_STICKS, ITEM_VINES, ITEM_REEDS, ITEM_STONES, ITEM_LOGS,
|
||||
ITEM_CLAY, ITEM_MEAT, ITEM_SKINS, ITEM_FEATHERS, ITEM_DOWN,
|
||||
ITEM_FISH, ITEM_SMOKED_FISH, ITEM_HEAL_SCROLL, ITEM_INCENSE, ITEM_BASKET_FOOD};
|
||||
int reward_item = possible_rewards[random(0, possible_rewards.length() - 1)];
|
||||
|
||||
int added_amount = 0;
|
||||
@@ -161,11 +182,16 @@ void apply_quest_reward(int score) {
|
||||
void run_quest(int quest_type) {
|
||||
p.pause_all();
|
||||
int score = 0;
|
||||
if (quest_type == QUEST_BAT_INVASION) score = run_bat_invasion();
|
||||
else if (quest_type == QUEST_CATCH_BOOMERANG) score = run_catch_the_boomerang();
|
||||
else if (quest_type == QUEST_ENCHANTED_MELODY) score = run_enchanted_melody();
|
||||
else if (quest_type == QUEST_ESCAPE_FROM_HEL) score = run_escape_from_hel();
|
||||
else if (quest_type == QUEST_SKELETAL_BARD) score = run_skeletal_bard();
|
||||
if (quest_type == QUEST_BAT_INVASION)
|
||||
score = run_bat_invasion();
|
||||
else if (quest_type == QUEST_CATCH_BOOMERANG)
|
||||
score = run_catch_the_boomerang();
|
||||
else if (quest_type == QUEST_ENCHANTED_MELODY)
|
||||
score = run_enchanted_melody();
|
||||
else if (quest_type == QUEST_ESCAPE_FROM_HEL)
|
||||
score = run_escape_from_hel();
|
||||
else if (quest_type == QUEST_SKELETAL_BARD)
|
||||
score = run_skeletal_bard();
|
||||
if (return_to_main_menu_requested) {
|
||||
p.resume_all();
|
||||
return;
|
||||
@@ -183,7 +209,7 @@ void run_quest_menu() {
|
||||
options.insert_last(get_quest_name(quest_queue[i]));
|
||||
}
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
wait(5);
|
||||
if (menu_background_tick()) {
|
||||
return;
|
||||
@@ -198,7 +224,8 @@ void run_quest_menu() {
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= options.length()) selection = 0;
|
||||
if (selection >= options.length())
|
||||
selection = 0;
|
||||
count_str = " " + (selection + 1) + " of " + options.length();
|
||||
speak_with_history(options[selection] + count_str, true);
|
||||
}
|
||||
@@ -206,7 +233,8 @@ void run_quest_menu() {
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0) selection = options.length() - 1;
|
||||
if (selection < 0)
|
||||
selection = options.length() - 1;
|
||||
count_str = " " + (selection + 1) + " of " + options.length();
|
||||
speak_with_history(options[selection] + count_str, true);
|
||||
}
|
||||
|
||||
@@ -60,12 +60,15 @@ int run_catch_the_boomerang() {
|
||||
if (key_pressed(KEY_SPACE)) {
|
||||
if (returning && boomerangY > -5) {
|
||||
int points = 5 + boomerangY;
|
||||
if (points < 1) points = 1;
|
||||
if (points > 4) points = 4;
|
||||
if (points < 1)
|
||||
points = 1;
|
||||
if (points > 4)
|
||||
points = 4;
|
||||
score += points;
|
||||
caughtCount++;
|
||||
string promptSuffix = (turn < turnsTotal - 1) ? " Press Space to throw." : "";
|
||||
speak_with_history("You " + skillLevel[points] + " the boomerang. " + points + " points." + promptSuffix, true);
|
||||
speak_with_history(
|
||||
"You " + skillLevel[points] + " the boomerang. " + points + " points." + promptSuffix, true);
|
||||
} else {
|
||||
string promptSuffix = (turn < turnsTotal - 1) ? " Press Space to throw." : "";
|
||||
speak_with_history("You missed the boomerang." + promptSuffix, true);
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
// Enchanted Melody quest game
|
||||
string[] quest_notes = {
|
||||
"sounds/quests/bone1.ogg",
|
||||
"sounds/quests/bone2.ogg",
|
||||
"sounds/quests/bone3.ogg",
|
||||
"sounds/quests/bone4.ogg"
|
||||
};
|
||||
string[] quest_notes = {"sounds/quests/bone1.ogg", "sounds/quests/bone2.ogg", "sounds/quests/bone3.ogg",
|
||||
"sounds/quests/bone4.ogg"};
|
||||
|
||||
void play_note(int note_index) {
|
||||
if (note_index < 0 || note_index >= int(quest_notes.length())) return;
|
||||
if (note_index < 0 || note_index >= int(quest_notes.length()))
|
||||
return;
|
||||
p.play_stationary(quest_notes[note_index], false);
|
||||
}
|
||||
|
||||
int get_note_from_key() {
|
||||
if (key_pressed(KEY_F) || key_pressed(KEY_K)) return 0;
|
||||
if (key_pressed(KEY_D) || key_pressed(KEY_J)) return 1;
|
||||
if (key_pressed(KEY_R) || key_pressed(KEY_I)) return 2;
|
||||
if (key_pressed(KEY_E) || key_pressed(KEY_U)) return 3;
|
||||
if (key_pressed(KEY_F) || key_pressed(KEY_K))
|
||||
return 0;
|
||||
if (key_pressed(KEY_D) || key_pressed(KEY_J))
|
||||
return 1;
|
||||
if (key_pressed(KEY_R) || key_pressed(KEY_I))
|
||||
return 2;
|
||||
if (key_pressed(KEY_E) || key_pressed(KEY_U))
|
||||
return 3;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -89,7 +90,8 @@ int run_enchanted_melody() {
|
||||
wait(5);
|
||||
handle_global_volume_keys();
|
||||
int note = get_note_from_key();
|
||||
if (note == -1) continue;
|
||||
if (note == -1)
|
||||
continue;
|
||||
play_note(note);
|
||||
if (note != pattern[index]) {
|
||||
int score = rounds * 2;
|
||||
|
||||
@@ -42,7 +42,8 @@ int run_escape_from_hel() {
|
||||
while (true) {
|
||||
// Speed increases indefinitely until player can't keep up
|
||||
int step_time = base_step_time - (total_steps * 8);
|
||||
if (step_time < 50) step_time = 50; // Minimum to prevent audio/timing issues
|
||||
if (step_time < 50)
|
||||
step_time = 50; // Minimum to prevent audio/timing issues
|
||||
|
||||
handle_global_volume_keys();
|
||||
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
// Skeletal Bard quest game
|
||||
string[] skeletalBardNotes = {
|
||||
"sounds/quests/bone1.ogg",
|
||||
"sounds/quests/bone2.ogg",
|
||||
"sounds/quests/bone3.ogg",
|
||||
"sounds/quests/bone4.ogg",
|
||||
"sounds/quests/bone5.ogg",
|
||||
"sounds/quests/bone6.ogg",
|
||||
"sounds/quests/bone7.ogg",
|
||||
"sounds/quests/bone8.ogg"
|
||||
};
|
||||
string[] skeletalBardNotes = {"sounds/quests/bone1.ogg", "sounds/quests/bone2.ogg", "sounds/quests/bone3.ogg",
|
||||
"sounds/quests/bone4.ogg", "sounds/quests/bone5.ogg", "sounds/quests/bone6.ogg",
|
||||
"sounds/quests/bone7.ogg", "sounds/quests/bone8.ogg"};
|
||||
|
||||
void play_skeletal_bard_note() {
|
||||
int noteIndex = random(0, skeletalBardNotes.length() - 1);
|
||||
@@ -26,12 +19,14 @@ int select_note_count(int minNotes, int maxNotes, int startValue) {
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
if (selection < maxNotes) selection++;
|
||||
if (selection < maxNotes)
|
||||
selection++;
|
||||
speak_with_history("" + selection + ".", true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
if (selection > minNotes) selection--;
|
||||
if (selection > minNotes)
|
||||
selection--;
|
||||
speak_with_history("" + selection + ".", true);
|
||||
}
|
||||
|
||||
@@ -78,13 +73,17 @@ int run_skeletal_bard() {
|
||||
return 0;
|
||||
}
|
||||
int diff = length - guess;
|
||||
if (diff < 0) diff = -diff;
|
||||
if (diff < 0)
|
||||
diff = -diff;
|
||||
|
||||
int points = 4 - diff;
|
||||
if (points < 0) points = 0;
|
||||
if (points < 0)
|
||||
points = 0;
|
||||
score += points;
|
||||
|
||||
speak_with_history("You entered " + guess + " notes and the actual number was " + length + ". " + points + " points. Press Enter to continue.", true);
|
||||
speak_with_history("You entered " + guess + " notes and the actual number was " + length + ". " + points +
|
||||
" points. Press Enter to continue.",
|
||||
true);
|
||||
while (true) {
|
||||
wait(5);
|
||||
handle_global_volume_keys();
|
||||
|
||||
+66
-31
@@ -38,15 +38,19 @@ int equipped_weapon_rune = RUNE_NONE;
|
||||
|
||||
// Get display name for a rune type
|
||||
string get_rune_name(int rune_type) {
|
||||
if (rune_type == RUNE_SWIFTNESS) return "Rune of Swiftness";
|
||||
if (rune_type == RUNE_DESTRUCTION) return "Rune of Destruction";
|
||||
if (rune_type == RUNE_SWIFTNESS)
|
||||
return "Rune of Swiftness";
|
||||
if (rune_type == RUNE_DESTRUCTION)
|
||||
return "Rune of Destruction";
|
||||
return "Unknown Rune";
|
||||
}
|
||||
|
||||
// Get the effect suffix for runed item names (e.g., "of Quickness")
|
||||
string get_rune_effect_name(int rune_type) {
|
||||
if (rune_type == RUNE_SWIFTNESS) return "Quickness";
|
||||
if (rune_type == RUNE_DESTRUCTION) return "Destruction";
|
||||
if (rune_type == RUNE_SWIFTNESS)
|
||||
return "Quickness";
|
||||
if (rune_type == RUNE_DESTRUCTION)
|
||||
return "Destruction";
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -57,23 +61,29 @@ bool any_rune_unlocked() {
|
||||
|
||||
// Check if a specific rune is unlocked
|
||||
bool is_rune_unlocked(int rune_type) {
|
||||
if (rune_type == RUNE_SWIFTNESS) return rune_swiftness_unlocked;
|
||||
if (rune_type == RUNE_DESTRUCTION) return rune_destruction_unlocked;
|
||||
if (rune_type == RUNE_SWIFTNESS)
|
||||
return rune_swiftness_unlocked;
|
||||
if (rune_type == RUNE_DESTRUCTION)
|
||||
return rune_destruction_unlocked;
|
||||
return false;
|
||||
}
|
||||
|
||||
void get_all_rune_types(int[]@ runeTypes) {
|
||||
if (@runeTypes == null) return;
|
||||
void get_all_rune_types(int[] @runeTypes) {
|
||||
if (@runeTypes == null)
|
||||
return;
|
||||
runeTypes.resize(0);
|
||||
runeTypes.insert_last(RUNE_SWIFTNESS);
|
||||
runeTypes.insert_last(RUNE_DESTRUCTION);
|
||||
}
|
||||
|
||||
void get_unlocked_rune_types(int[]@ runeTypes) {
|
||||
if (@runeTypes == null) return;
|
||||
void get_unlocked_rune_types(int[] @runeTypes) {
|
||||
if (@runeTypes == null)
|
||||
return;
|
||||
runeTypes.resize(0);
|
||||
if (rune_swiftness_unlocked) runeTypes.insert_last(RUNE_SWIFTNESS);
|
||||
if (rune_destruction_unlocked) runeTypes.insert_last(RUNE_DESTRUCTION);
|
||||
if (rune_swiftness_unlocked)
|
||||
runeTypes.insert_last(RUNE_SWIFTNESS);
|
||||
if (rune_destruction_unlocked)
|
||||
runeTypes.insert_last(RUNE_DESTRUCTION);
|
||||
}
|
||||
|
||||
// Create dictionary key for runed item storage
|
||||
@@ -111,7 +121,8 @@ bool has_any_runed_version(int equip_type) {
|
||||
int[] runeTypes;
|
||||
get_all_rune_types(runeTypes);
|
||||
for (uint i = 0; i < runeTypes.length(); i++) {
|
||||
if (get_runed_item_count(equip_type, runeTypes[i]) > 0) return true;
|
||||
if (get_runed_item_count(equip_type, runeTypes[i]) > 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -144,7 +155,8 @@ void remove_stored_runed_item(int equip_type, int rune_type) {
|
||||
// Deposit runed item from personal inventory to storage
|
||||
bool deposit_runed_item(int equip_type, int rune_type) {
|
||||
int personal = get_runed_item_count(equip_type, rune_type);
|
||||
if (personal <= 0) return false;
|
||||
if (personal <= 0)
|
||||
return false;
|
||||
|
||||
remove_runed_item(equip_type, rune_type);
|
||||
add_stored_runed_item(equip_type, rune_type);
|
||||
@@ -154,7 +166,8 @@ bool deposit_runed_item(int equip_type, int rune_type) {
|
||||
// Withdraw runed item from storage to personal inventory
|
||||
bool withdraw_runed_item(int equip_type, int rune_type) {
|
||||
int stored = get_stored_runed_item_count(equip_type, rune_type);
|
||||
if (stored <= 0) return false;
|
||||
if (stored <= 0)
|
||||
return false;
|
||||
|
||||
remove_stored_runed_item(equip_type, rune_type);
|
||||
add_runed_item(equip_type, rune_type);
|
||||
@@ -163,32 +176,54 @@ bool withdraw_runed_item(int equip_type, int rune_type) {
|
||||
|
||||
// Get the rune type on equipped item for a given slot
|
||||
int get_equipped_rune_for_slot(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE ||
|
||||
equip_type == EQUIP_SLING || equip_type == EQUIP_BOW) {
|
||||
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE || equip_type == EQUIP_SLING || equip_type == EQUIP_BOW) {
|
||||
return equipped_weapon_rune;
|
||||
}
|
||||
if (equip_type == EQUIP_HAT) return equipped_head_rune;
|
||||
if (equip_type == EQUIP_TUNIC) return equipped_torso_rune;
|
||||
if (equip_type == EQUIP_POUCH || equip_type == EQUIP_BACKPACK) return equipped_arms_rune;
|
||||
if (equip_type == EQUIP_GLOVES) return equipped_hands_rune;
|
||||
if (equip_type == EQUIP_PANTS) return equipped_legs_rune;
|
||||
if (equip_type == EQUIP_MOCCASINS) return equipped_feet_rune;
|
||||
if (equip_type == EQUIP_HAT)
|
||||
return equipped_head_rune;
|
||||
if (equip_type == EQUIP_TUNIC)
|
||||
return equipped_torso_rune;
|
||||
if (equip_type == EQUIP_POUCH || equip_type == EQUIP_BACKPACK)
|
||||
return equipped_arms_rune;
|
||||
if (equip_type == EQUIP_GLOVES)
|
||||
return equipped_hands_rune;
|
||||
if (equip_type == EQUIP_PANTS)
|
||||
return equipped_legs_rune;
|
||||
if (equip_type == EQUIP_MOCCASINS)
|
||||
return equipped_feet_rune;
|
||||
return RUNE_NONE;
|
||||
}
|
||||
|
||||
// Set the rune on an equipped item slot
|
||||
void set_equipped_rune_for_slot(int equip_type, int rune_type) {
|
||||
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE ||
|
||||
equip_type == EQUIP_SLING || equip_type == EQUIP_BOW) {
|
||||
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE || equip_type == EQUIP_SLING || equip_type == EQUIP_BOW) {
|
||||
equipped_weapon_rune = rune_type;
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_HAT) { equipped_head_rune = rune_type; return; }
|
||||
if (equip_type == EQUIP_TUNIC) { equipped_torso_rune = rune_type; return; }
|
||||
if (equip_type == EQUIP_POUCH || equip_type == EQUIP_BACKPACK) { equipped_arms_rune = rune_type; return; }
|
||||
if (equip_type == EQUIP_GLOVES) { equipped_hands_rune = rune_type; return; }
|
||||
if (equip_type == EQUIP_PANTS) { equipped_legs_rune = rune_type; return; }
|
||||
if (equip_type == EQUIP_MOCCASINS) { equipped_feet_rune = rune_type; return; }
|
||||
if (equip_type == EQUIP_HAT) {
|
||||
equipped_head_rune = rune_type;
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_TUNIC) {
|
||||
equipped_torso_rune = rune_type;
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_POUCH || equip_type == EQUIP_BACKPACK) {
|
||||
equipped_arms_rune = rune_type;
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_GLOVES) {
|
||||
equipped_hands_rune = rune_type;
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_PANTS) {
|
||||
equipped_legs_rune = rune_type;
|
||||
return;
|
||||
}
|
||||
if (equip_type == EQUIP_MOCCASINS) {
|
||||
equipped_feet_rune = rune_type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear rune from an equipped slot
|
||||
|
||||
+50
-25
@@ -8,13 +8,20 @@ int get_total_rune_walk_speed_bonus() {
|
||||
int bonus = 0;
|
||||
|
||||
// Check each equipment slot for swiftness runes
|
||||
if (equipped_head_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_torso_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_arms_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_hands_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_legs_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_feet_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_weapon_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_head_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_torso_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_arms_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_hands_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_legs_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_feet_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
if (equipped_weapon_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
|
||||
|
||||
return bonus;
|
||||
}
|
||||
@@ -25,13 +32,20 @@ int get_total_rune_gather_bonus() {
|
||||
int bonus = 0;
|
||||
|
||||
// Check each equipment slot for swiftness runes
|
||||
if (equipped_head_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_torso_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_arms_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_hands_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_legs_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_feet_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_weapon_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_head_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_torso_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_arms_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_hands_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_legs_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_feet_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
if (equipped_weapon_rune == RUNE_SWIFTNESS)
|
||||
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
|
||||
|
||||
return bonus;
|
||||
}
|
||||
@@ -43,10 +57,12 @@ int apply_rune_gather_bonus(int base_time) {
|
||||
if (blessing_search_active) {
|
||||
bonus_percent += BLESSING_SEARCH_GATHER_BONUS;
|
||||
}
|
||||
if (bonus_percent <= 0) return base_time;
|
||||
if (bonus_percent <= 0)
|
||||
return base_time;
|
||||
|
||||
// Keep gathering from becoming instant.
|
||||
if (bonus_percent > GATHER_TIME_REDUCTION_CAP) bonus_percent = GATHER_TIME_REDUCTION_CAP;
|
||||
if (bonus_percent > GATHER_TIME_REDUCTION_CAP)
|
||||
bonus_percent = GATHER_TIME_REDUCTION_CAP;
|
||||
|
||||
int reduction = (base_time * bonus_percent) / 100;
|
||||
return base_time - reduction;
|
||||
@@ -55,13 +71,20 @@ int apply_rune_gather_bonus(int base_time) {
|
||||
// Count total equipped swiftness runes
|
||||
int count_equipped_swiftness_runes() {
|
||||
int count = 0;
|
||||
if (equipped_head_rune == RUNE_SWIFTNESS) count++;
|
||||
if (equipped_torso_rune == RUNE_SWIFTNESS) count++;
|
||||
if (equipped_arms_rune == RUNE_SWIFTNESS) count++;
|
||||
if (equipped_hands_rune == RUNE_SWIFTNESS) count++;
|
||||
if (equipped_legs_rune == RUNE_SWIFTNESS) count++;
|
||||
if (equipped_feet_rune == RUNE_SWIFTNESS) count++;
|
||||
if (equipped_weapon_rune == RUNE_SWIFTNESS) count++;
|
||||
if (equipped_head_rune == RUNE_SWIFTNESS)
|
||||
count++;
|
||||
if (equipped_torso_rune == RUNE_SWIFTNESS)
|
||||
count++;
|
||||
if (equipped_arms_rune == RUNE_SWIFTNESS)
|
||||
count++;
|
||||
if (equipped_hands_rune == RUNE_SWIFTNESS)
|
||||
count++;
|
||||
if (equipped_legs_rune == RUNE_SWIFTNESS)
|
||||
count++;
|
||||
if (equipped_feet_rune == RUNE_SWIFTNESS)
|
||||
count++;
|
||||
if (equipped_weapon_rune == RUNE_SWIFTNESS)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -79,14 +102,16 @@ string get_rune_speed_description() {
|
||||
desc += walk_bonus + "ms faster walking";
|
||||
}
|
||||
if (gather_bonus > 0) {
|
||||
if (desc.length() > 0) desc += ", ";
|
||||
if (desc.length() > 0)
|
||||
desc += ", ";
|
||||
desc += gather_bonus + "% faster gathering";
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
int apply_weapon_rune_damage(int baseDamage) {
|
||||
if (baseDamage <= 0) return baseDamage;
|
||||
if (baseDamage <= 0)
|
||||
return baseDamage;
|
||||
if (equipped_weapon_rune == RUNE_DESTRUCTION) {
|
||||
return baseDamage * RUNE_DESTRUCTION_DAMAGE_MULTIPLIER;
|
||||
}
|
||||
|
||||
+407
-178
File diff suppressed because it is too large
Load Diff
@@ -4,14 +4,17 @@ string get_terrain_at_position(int posX) {
|
||||
return "water";
|
||||
}
|
||||
|
||||
MountainRange@ mountain = get_mountain_at(posX);
|
||||
MountainRange @mountain = get_mountain_at(posX);
|
||||
if (mountain !is null) {
|
||||
return mountain.get_terrain_at(posX);
|
||||
}
|
||||
|
||||
if (posX <= BASE_END) return "wood";
|
||||
if (posX <= GRASS_END) return "grass";
|
||||
if (posX <= GRAVEL_END) return "gravel";
|
||||
if (posX <= BASE_END)
|
||||
return "wood";
|
||||
if (posX <= GRASS_END)
|
||||
return "grass";
|
||||
if (posX <= GRAVEL_END)
|
||||
return "gravel";
|
||||
|
||||
int index = posX - expanded_area_start;
|
||||
if (index >= 0 && index < int(expanded_terrain_types.length())) {
|
||||
|
||||
+161
-85
@@ -95,15 +95,17 @@ void reset_player_item_break_state() {
|
||||
reset_player_item_break_audio_state();
|
||||
}
|
||||
|
||||
void queue_player_item_break_message(const string&in message) {
|
||||
if (message.length() == 0) return;
|
||||
void queue_player_item_break_message(const string& in message) {
|
||||
if (message.length() == 0)
|
||||
return;
|
||||
playerItemBreakMessage = message;
|
||||
playerItemBreakSoundHandle = p.play_stationary("sounds/items/item_breaks.ogg", false);
|
||||
playerItemBreakSoundPending = true;
|
||||
}
|
||||
|
||||
void update_player_item_break_message() {
|
||||
if (!playerItemBreakSoundPending) return;
|
||||
if (!playerItemBreakSoundPending)
|
||||
return;
|
||||
if (playerItemBreakSoundHandle != -1 && p.sound_is_active(playerItemBreakSoundHandle)) {
|
||||
return;
|
||||
}
|
||||
@@ -116,8 +118,10 @@ void update_player_item_break_message() {
|
||||
}
|
||||
|
||||
void resolve_pending_player_item_break() {
|
||||
if (!playerItemBreakPending) return;
|
||||
if (x > BASE_END) return;
|
||||
if (!playerItemBreakPending)
|
||||
return;
|
||||
if (x > BASE_END)
|
||||
return;
|
||||
if (playerItemBreakPendingType == -1) {
|
||||
playerItemBreakPending = false;
|
||||
return;
|
||||
@@ -132,12 +136,15 @@ void resolve_pending_player_item_break() {
|
||||
}
|
||||
|
||||
void attempt_player_item_break_check() {
|
||||
if (playerItemBreakPending) return;
|
||||
if (playerItemBreaksToday >= PLAYER_ITEM_BREAKS_PER_DAY) return;
|
||||
if (playerItemBreakPending)
|
||||
return;
|
||||
if (playerItemBreaksToday >= PLAYER_ITEM_BREAKS_PER_DAY)
|
||||
return;
|
||||
|
||||
int[] breakableItems;
|
||||
get_breakable_personal_item_types(breakableItems);
|
||||
if (breakableItems.length() == 0) return;
|
||||
if (breakableItems.length() == 0)
|
||||
return;
|
||||
|
||||
int roll = random(1, PLAYER_ITEM_BREAK_ROLL_MAX);
|
||||
int checkChance = int(playerItemBreakChance); // Floor for comparison
|
||||
@@ -167,7 +174,7 @@ void attempt_player_item_break_check() {
|
||||
}
|
||||
}
|
||||
|
||||
string get_invasion_enemy_type_for_terrain(const string&in terrain_type) {
|
||||
string get_invasion_enemy_type_for_terrain(const string& in terrain_type) {
|
||||
for (uint i = 0; i < invasion_terrain_enemy_map.length(); i++) {
|
||||
string entry = invasion_terrain_enemy_map[i];
|
||||
int eq_pos = entry.find("=");
|
||||
@@ -184,12 +191,13 @@ string get_invasion_enemy_type_for_terrain(const string&in terrain_type) {
|
||||
return default_invasion_enemy_type;
|
||||
}
|
||||
|
||||
string get_invasion_enemy_label(const string&in enemy_type) {
|
||||
if (enemy_type != "") return enemy_type;
|
||||
string get_invasion_enemy_label(const string& in enemy_type) {
|
||||
if (enemy_type != "")
|
||||
return enemy_type;
|
||||
return default_invasion_enemy_type;
|
||||
}
|
||||
|
||||
string get_invasion_enemy_plural(const string&in enemy_type) {
|
||||
string get_invasion_enemy_plural(const string& in enemy_type) {
|
||||
return get_invasion_enemy_label(enemy_type) + "s";
|
||||
}
|
||||
|
||||
@@ -257,11 +265,18 @@ string expand_regular_area() {
|
||||
// Fill the new area up to its tree cap with proper spacing
|
||||
spawn_trees(new_start, new_end);
|
||||
} else {
|
||||
// Keep both extreme edge tiles dry so area transitions are never blocked.
|
||||
int max_stream_width = EXPANSION_SIZE - 2;
|
||||
if (max_stream_width > 0) {
|
||||
int stream_width = random(1, 5);
|
||||
int stream_start = random(0, EXPANSION_SIZE - stream_width);
|
||||
if (stream_width > max_stream_width) {
|
||||
stream_width = max_stream_width;
|
||||
}
|
||||
int stream_start = random(1, EXPANSION_SIZE - stream_width - 1);
|
||||
int actual_start = new_start + stream_start;
|
||||
add_world_stream(actual_start, stream_width);
|
||||
}
|
||||
}
|
||||
|
||||
area_expanded_today = true;
|
||||
notify("The area has expanded! New territory discovered to the east.");
|
||||
@@ -280,7 +295,7 @@ void expand_mountain() {
|
||||
MAP_SIZE += size;
|
||||
|
||||
// Generate mountain range
|
||||
MountainRange@ mountain = MountainRange(new_start, size);
|
||||
MountainRange @mountain = MountainRange(new_start, size);
|
||||
world_mountains.insert_last(mountain);
|
||||
|
||||
// Fill terrain types array for compatibility with save system
|
||||
@@ -343,14 +358,17 @@ void update_invasion_chance_for_new_day() {
|
||||
invasion_chance = 25;
|
||||
} else {
|
||||
invasion_chance += 25;
|
||||
if (invasion_chance > 100) invasion_chance = 100;
|
||||
if (invasion_chance > 100)
|
||||
invasion_chance = 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get_random_invasion_hour(int min_hour) {
|
||||
if (min_hour < 6) min_hour = 6;
|
||||
if (min_hour > 11) return -1;
|
||||
if (min_hour < 6)
|
||||
min_hour = 6;
|
||||
if (min_hour > 11)
|
||||
return -1;
|
||||
return random(min_hour, 11);
|
||||
}
|
||||
|
||||
@@ -359,7 +377,8 @@ bool is_night_hour(int hour) {
|
||||
}
|
||||
|
||||
int get_random_zombie_swarm_hour(int min_hour) {
|
||||
if (!is_night_hour(min_hour)) return -1;
|
||||
if (!is_night_hour(min_hour))
|
||||
return -1;
|
||||
if (min_hour >= 19) {
|
||||
return random(min_hour, 23);
|
||||
}
|
||||
@@ -367,14 +386,17 @@ int get_random_zombie_swarm_hour(int min_hour) {
|
||||
}
|
||||
|
||||
void schedule_invasion() {
|
||||
if (invasion_scheduled_hour != -1) return;
|
||||
if (invasion_scheduled_hour != -1)
|
||||
return;
|
||||
int hour = get_random_invasion_hour(current_hour);
|
||||
if (hour == -1) return;
|
||||
if (hour == -1)
|
||||
return;
|
||||
invasion_scheduled_hour = hour;
|
||||
}
|
||||
|
||||
void check_scheduled_invasion() {
|
||||
if (invasion_active) return;
|
||||
if (invasion_active)
|
||||
return;
|
||||
|
||||
// Check scheduled invasion regardless of triggered flag (fixes bug where flag was set early in old saves)
|
||||
if (invasion_scheduled_hour != -1) {
|
||||
@@ -388,19 +410,25 @@ void check_scheduled_invasion() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (invasion_triggered_today) return;
|
||||
if (invasion_triggered_today)
|
||||
return;
|
||||
}
|
||||
|
||||
void attempt_daily_invasion() {
|
||||
if (current_day < 2) return;
|
||||
if (invasion_triggered_today || invasion_active) return;
|
||||
if (invasion_roll_done_today) return;
|
||||
if (current_hour < 6 || current_hour > 12) return;
|
||||
if (current_day < 2)
|
||||
return;
|
||||
if (invasion_triggered_today || invasion_active)
|
||||
return;
|
||||
if (invasion_roll_done_today)
|
||||
return;
|
||||
if (current_hour < 6 || current_hour > 12)
|
||||
return;
|
||||
|
||||
invasion_roll_done_today = true;
|
||||
|
||||
int roll = random(1, 100);
|
||||
if (roll > invasion_chance) return;
|
||||
if (roll > invasion_chance)
|
||||
return;
|
||||
|
||||
schedule_invasion();
|
||||
check_scheduled_invasion();
|
||||
@@ -412,20 +440,25 @@ bool can_roll_zombie_swarm_today() {
|
||||
|
||||
int get_zombie_swarm_duration_hours() {
|
||||
int offset = current_day - ZOMBIE_SWARM_START_DAY;
|
||||
if (offset < 0) offset = 0;
|
||||
if (offset < 0)
|
||||
offset = 0;
|
||||
int cycles = offset / ZOMBIE_SWARM_INTERVAL_DAYS;
|
||||
int duration = ZOMBIE_SWARM_BASE_DURATION_HOURS + (cycles * ZOMBIE_SWARM_DURATION_STEP_HOURS);
|
||||
if (duration < 1) duration = 1;
|
||||
if (duration < 1)
|
||||
duration = 1;
|
||||
return duration;
|
||||
}
|
||||
|
||||
int get_zombie_swarm_chance_for_day() {
|
||||
int offset = current_day - ZOMBIE_SWARM_START_DAY;
|
||||
if (offset < 0) offset = 0;
|
||||
if (offset < 0)
|
||||
offset = 0;
|
||||
int cycles = offset / ZOMBIE_SWARM_CHANCE_INTERVAL_DAYS;
|
||||
int chance = ZOMBIE_SWARM_CHANCE_START + (cycles * ZOMBIE_SWARM_CHANCE_STEP);
|
||||
if (chance > ZOMBIE_SWARM_CHANCE_CAP) chance = ZOMBIE_SWARM_CHANCE_CAP;
|
||||
if (chance < 0) chance = 0;
|
||||
if (chance > ZOMBIE_SWARM_CHANCE_CAP)
|
||||
chance = ZOMBIE_SWARM_CHANCE_CAP;
|
||||
if (chance < 0)
|
||||
chance = 0;
|
||||
return chance;
|
||||
}
|
||||
|
||||
@@ -443,7 +476,8 @@ void end_zombie_swarm() {
|
||||
}
|
||||
|
||||
void check_zombie_swarm_status() {
|
||||
if (!zombie_swarm_active) return;
|
||||
if (!zombie_swarm_active)
|
||||
return;
|
||||
if (!is_night_hour(current_hour)) {
|
||||
end_zombie_swarm();
|
||||
return;
|
||||
@@ -458,14 +492,17 @@ void check_zombie_swarm_status() {
|
||||
}
|
||||
|
||||
void schedule_zombie_swarm() {
|
||||
if (zombie_swarm_scheduled_hour != -1) return;
|
||||
if (zombie_swarm_scheduled_hour != -1)
|
||||
return;
|
||||
int hour = get_random_zombie_swarm_hour(current_hour);
|
||||
if (hour == -1) return;
|
||||
if (hour == -1)
|
||||
return;
|
||||
zombie_swarm_scheduled_hour = hour;
|
||||
}
|
||||
|
||||
void check_scheduled_zombie_swarm() {
|
||||
if (zombie_swarm_active) return;
|
||||
if (zombie_swarm_active)
|
||||
return;
|
||||
if (zombie_swarm_scheduled_hour != -1) {
|
||||
if (!is_night_hour(zombie_swarm_scheduled_hour) || !is_night_hour(current_hour)) {
|
||||
zombie_swarm_scheduled_hour = -1;
|
||||
@@ -478,13 +515,17 @@ void check_scheduled_zombie_swarm() {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (zombie_swarm_triggered_today) return;
|
||||
if (zombie_swarm_triggered_today)
|
||||
return;
|
||||
}
|
||||
|
||||
void attempt_daily_zombie_swarm() {
|
||||
if (!can_roll_zombie_swarm_today()) return;
|
||||
if (zombie_swarm_roll_done_today || zombie_swarm_triggered_today || zombie_swarm_active) return;
|
||||
if (!is_night_hour(current_hour)) return;
|
||||
if (!can_roll_zombie_swarm_today())
|
||||
return;
|
||||
if (zombie_swarm_roll_done_today || zombie_swarm_triggered_today || zombie_swarm_active)
|
||||
return;
|
||||
if (!is_night_hour(current_hour))
|
||||
return;
|
||||
|
||||
zombie_swarm_roll_done_today = true;
|
||||
int chance = get_zombie_swarm_chance_for_day();
|
||||
@@ -503,13 +544,15 @@ void attempt_daily_zombie_swarm() {
|
||||
check_scheduled_zombie_swarm();
|
||||
}
|
||||
|
||||
void get_expanded_area_segments(int[]@ areaStarts, int[]@ areaEnds, string[]@ areaTypes) {
|
||||
void get_expanded_area_segments(int[] @areaStarts, int[] @areaEnds, string[] @areaTypes) {
|
||||
areaStarts.resize(0);
|
||||
areaEnds.resize(0);
|
||||
areaTypes.resize(0);
|
||||
if (expanded_area_start == -1) return;
|
||||
if (expanded_area_start == -1)
|
||||
return;
|
||||
int total = int(expanded_terrain_types.length());
|
||||
if (total <= 0) return;
|
||||
if (total <= 0)
|
||||
return;
|
||||
|
||||
string current_type = get_expanded_area_type(0);
|
||||
int segment_start = 0;
|
||||
@@ -530,21 +573,28 @@ void get_expanded_area_segments(int[]@ areaStarts, int[]@ areaEnds, string[]@ ar
|
||||
}
|
||||
|
||||
void attempt_expansion_roamer_spawn() {
|
||||
if (!is_daytime) return;
|
||||
if (invasion_active) return;
|
||||
if (!invasion_started_once) return;
|
||||
if (expanded_area_start == -1) return;
|
||||
if (current_hour % EXPANSION_ROAMER_SPAWN_INTERVAL_HOURS != 0) return;
|
||||
if (!is_daytime)
|
||||
return;
|
||||
if (invasion_active)
|
||||
return;
|
||||
if (!invasion_started_once)
|
||||
return;
|
||||
if (expanded_area_start == -1)
|
||||
return;
|
||||
if (current_hour % EXPANSION_ROAMER_SPAWN_INTERVAL_HOURS != 0)
|
||||
return;
|
||||
|
||||
int[] areaStarts;
|
||||
int[] areaEnds;
|
||||
string[] areaTypes;
|
||||
get_expanded_area_segments(areaStarts, areaEnds, areaTypes);
|
||||
if (areaStarts.length() == 0) return;
|
||||
if (areaStarts.length() == 0)
|
||||
return;
|
||||
|
||||
for (uint i = 0; i < areaStarts.length(); i++) {
|
||||
int count = count_bandits_in_range(areaStarts[i], areaEnds[i]);
|
||||
if (count >= EXPANSION_ROAMER_MAX_PER_AREA) continue;
|
||||
if (count >= EXPANSION_ROAMER_MAX_PER_AREA)
|
||||
continue;
|
||||
string invader_type = get_invasion_enemy_type_for_terrain(areaTypes[i]);
|
||||
spawn_bandit(areaStarts[i], areaEnds[i], invader_type);
|
||||
}
|
||||
@@ -588,7 +638,8 @@ void attempt_resident_recruitment() {
|
||||
added = MAX_RESIDENTS - residents_count;
|
||||
}
|
||||
|
||||
if (added <= 0) return;
|
||||
if (added <= 0)
|
||||
return;
|
||||
|
||||
residents_count += added;
|
||||
string join_message = (added == 1) ? "A survivor joins your base." : "" + added + " survivors join your base.";
|
||||
@@ -617,13 +668,15 @@ void transition_bandits_to_wandering() {
|
||||
}
|
||||
bandits[i].behavior_state = "wandering";
|
||||
bandits[i].wander_direction = random(-1, 1);
|
||||
bandits[i].wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
|
||||
bandits[i].wander_direction_change_interval =
|
||||
random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
|
||||
bandits[i].wander_direction_timer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
void check_invasion_status() {
|
||||
if (!invasion_active) return;
|
||||
if (!invasion_active)
|
||||
return;
|
||||
|
||||
// Check if invasion duration has elapsed
|
||||
int hours_elapsed = current_hour - invasion_start_hour;
|
||||
@@ -669,32 +722,40 @@ void update_blessings() {
|
||||
}
|
||||
|
||||
void attempt_blessing() {
|
||||
if (favor < 1.0) return;
|
||||
if (favor < 1.0)
|
||||
return;
|
||||
int roll = random(1, 100);
|
||||
if (roll > BLESSING_TRIGGER_CHANCE) return;
|
||||
if (roll > BLESSING_TRIGGER_CHANCE)
|
||||
return;
|
||||
|
||||
int[] options;
|
||||
if (player_health < max_health) options.insert_last(0);
|
||||
if (!blessing_speed_active) options.insert_last(1);
|
||||
if (barricade_health < BARRICADE_MAX_HEALTH) options.insert_last(2);
|
||||
if (residents_count > 0 && !blessing_resident_active) options.insert_last(3);
|
||||
if (!blessing_search_active) options.insert_last(4);
|
||||
if (options.length() == 0) return;
|
||||
if (player_health < max_health)
|
||||
options.insert_last(0);
|
||||
if (!blessing_speed_active)
|
||||
options.insert_last(1);
|
||||
if (barricade_health < BARRICADE_MAX_HEALTH)
|
||||
options.insert_last(2);
|
||||
if (residents_count > 0 && !blessing_resident_active)
|
||||
options.insert_last(3);
|
||||
if (!blessing_search_active)
|
||||
options.insert_last(4);
|
||||
if (options.length() == 0)
|
||||
return;
|
||||
|
||||
int choice = options[random(0, options.length() - 1)];
|
||||
favor -= 1.0;
|
||||
if (favor < 0) favor = 0;
|
||||
if (favor < 0)
|
||||
favor = 0;
|
||||
|
||||
string[] god_names = {
|
||||
"Odin's", "Thor's", "Freyja's", "Loki's", "Tyr's", "Baldur's",
|
||||
"Frigg's", "Heimdall's", "Hel's", "Fenrir's", "Freyr's", "The gods'"
|
||||
};
|
||||
string[] god_names = {"Odin's", "Thor's", "Freyja's", "Loki's", "Tyr's", "Baldur's",
|
||||
"Frigg's", "Heimdall's", "Hel's", "Fenrir's", "Freyr's", "The gods'"};
|
||||
string god_name = god_names[random(0, god_names.length() - 1)];
|
||||
|
||||
if (choice == 0) {
|
||||
int before = player_health;
|
||||
player_health += BLESSING_HEAL_AMOUNT;
|
||||
if (player_health > max_health) player_health = max_health;
|
||||
if (player_health > max_health)
|
||||
player_health = max_health;
|
||||
int healed = player_health - before;
|
||||
string bonus = (healed > 0) ? "You feel restored. +" + healed + " health." : "You feel restored.";
|
||||
notify(god_name + " favor shines upon you. " + bonus);
|
||||
@@ -705,8 +766,7 @@ void attempt_blessing() {
|
||||
notify(god_name + " favor shines upon you. You feel swift for a while.");
|
||||
} else if (choice == 2) {
|
||||
int gained = add_barricade_health(BLESSING_BARRICADE_REPAIR);
|
||||
string bonus = (gained > 0)
|
||||
? "A divine force repairs the barricade. +" + gained + " health."
|
||||
string bonus = (gained > 0) ? "A divine force repairs the barricade. +" + gained + " health."
|
||||
: "A divine force surrounds the barricade.";
|
||||
notify(god_name + " favor shines upon you. " + bonus);
|
||||
} else if (choice == 3) {
|
||||
@@ -722,12 +782,17 @@ void attempt_blessing() {
|
||||
|
||||
bool should_attempt_resident_foraging(int hour) {
|
||||
int residentCount = residents_count;
|
||||
if (residentCount <= 0) return false;
|
||||
if (residentCount <= 0)
|
||||
return false;
|
||||
|
||||
if (hour == 6) return true;
|
||||
if (residentCount == 1) return false;
|
||||
if (residentCount == 2) return hour == 12;
|
||||
if (residentCount == 3) return hour == 12 || hour == 18;
|
||||
if (hour == 6)
|
||||
return true;
|
||||
if (residentCount == 1)
|
||||
return false;
|
||||
if (residentCount == 2)
|
||||
return hour == 12;
|
||||
if (residentCount == 3)
|
||||
return hour == 12 || hour == 18;
|
||||
|
||||
// 4+ residents: spread across daytime hours
|
||||
return hour == 10 || hour == 14 || hour == 18;
|
||||
@@ -794,7 +859,8 @@ void update_time() {
|
||||
if (current_hour >= day_start_hour && current_hour < day_end_hour) {
|
||||
int repair_window_hours = day_end_hour - day_start_hour;
|
||||
int interval = repair_window_hours / residents_count;
|
||||
if (interval < 1) interval = 1;
|
||||
if (interval < 1)
|
||||
interval = 1;
|
||||
int day_hour = current_hour - day_start_hour;
|
||||
if (day_hour % interval == 0) {
|
||||
if (has_any_storage_food()) {
|
||||
@@ -854,7 +920,8 @@ void update_time() {
|
||||
}
|
||||
|
||||
void update_incense_burning() {
|
||||
if (!incense_burning || incense_hours_remaining <= 0) return;
|
||||
if (!incense_burning || incense_hours_remaining <= 0)
|
||||
return;
|
||||
|
||||
favor += INCENSE_FAVOR_PER_HOUR;
|
||||
incense_hours_remaining--;
|
||||
@@ -964,7 +1031,8 @@ void start_crossfade(bool to_night) {
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -996,7 +1064,8 @@ void update_crossfade() {
|
||||
}
|
||||
|
||||
float progress = float(crossfade_timer.elapsed) / float(CROSSFADE_DURATION);
|
||||
if (progress > 1.0) progress = 1.0;
|
||||
if (progress > 1.0)
|
||||
progress = 1.0;
|
||||
|
||||
// Volume interpolation: use a slow-start curve to make fade-outs more gradual
|
||||
float volume_range = CROSSFADE_MAX_VOLUME - CROSSFADE_MIN_VOLUME; // dB range
|
||||
@@ -1006,12 +1075,16 @@ void update_crossfade() {
|
||||
|
||||
if (crossfade_to_night) {
|
||||
// Fading day out, night in
|
||||
if (day_sound_handle != -1) p.update_sound_start_values(day_sound_handle, 0.0, fade_out_vol, 1.0);
|
||||
if (night_sound_handle != -1) p.update_sound_start_values(night_sound_handle, 0.0, fade_in_vol, 1.0);
|
||||
if (day_sound_handle != -1)
|
||||
p.update_sound_start_values(day_sound_handle, 0.0, fade_out_vol, 1.0);
|
||||
if (night_sound_handle != -1)
|
||||
p.update_sound_start_values(night_sound_handle, 0.0, fade_in_vol, 1.0);
|
||||
} else {
|
||||
// Fading night out, day in
|
||||
if (night_sound_handle != -1) p.update_sound_start_values(night_sound_handle, 0.0, fade_out_vol, 1.0);
|
||||
if (day_sound_handle != -1) p.update_sound_start_values(day_sound_handle, 0.0, fade_in_vol, 1.0);
|
||||
if (night_sound_handle != -1)
|
||||
p.update_sound_start_values(night_sound_handle, 0.0, fade_out_vol, 1.0);
|
||||
if (day_sound_handle != -1)
|
||||
p.update_sound_start_values(day_sound_handle, 0.0, fade_in_vol, 1.0);
|
||||
}
|
||||
|
||||
// Complete the crossfade
|
||||
@@ -1029,7 +1102,8 @@ void complete_crossfade() {
|
||||
p.destroy_sound(day_sound_handle);
|
||||
day_sound_handle = -1;
|
||||
}
|
||||
if (night_sound_handle != -1) p.update_sound_start_values(night_sound_handle, 0.0, 0.0, 1.0);
|
||||
if (night_sound_handle != -1)
|
||||
p.update_sound_start_values(night_sound_handle, 0.0, 0.0, 1.0);
|
||||
is_daytime = false;
|
||||
if (night_sound_handle == -1 || !p.sound_is_active(night_sound_handle)) {
|
||||
update_ambience(false);
|
||||
@@ -1040,7 +1114,8 @@ void complete_crossfade() {
|
||||
p.destroy_sound(night_sound_handle);
|
||||
night_sound_handle = -1;
|
||||
}
|
||||
if (day_sound_handle != -1) p.update_sound_start_values(day_sound_handle, 0.0, 0.0, 1.0);
|
||||
if (day_sound_handle != -1)
|
||||
p.update_sound_start_values(day_sound_handle, 0.0, 0.0, 1.0);
|
||||
is_daytime = true;
|
||||
if (day_sound_handle == -1 || !p.sound_is_active(day_sound_handle)) {
|
||||
update_ambience(false);
|
||||
@@ -1049,7 +1124,8 @@ void complete_crossfade() {
|
||||
}
|
||||
|
||||
void ensure_ambience_running() {
|
||||
if (crossfade_active) return;
|
||||
if (crossfade_active)
|
||||
return;
|
||||
|
||||
if (is_daytime) {
|
||||
if (day_sound_handle == -1 || !p.sound_is_active(day_sound_handle)) {
|
||||
|
||||
+21
-13
@@ -3,32 +3,39 @@
|
||||
|
||||
funcdef void WeaponRangeAudioCallback();
|
||||
|
||||
WeaponRangeAudioCallback@[] weapon_range_audio_callbacks;
|
||||
WeaponRangeAudioCallback @[] weapon_range_audio_callbacks;
|
||||
bool weapon_range_audio_initialized = false;
|
||||
|
||||
void init_weapon_range_audio_registry() {
|
||||
if (weapon_range_audio_initialized) return;
|
||||
if (weapon_range_audio_initialized)
|
||||
return;
|
||||
weapon_range_audio_callbacks.resize(0);
|
||||
weapon_range_audio_initialized = true;
|
||||
}
|
||||
|
||||
bool register_weapon_range_audio_callback(WeaponRangeAudioCallback@ callback) {
|
||||
bool register_weapon_range_audio_callback(WeaponRangeAudioCallback @callback) {
|
||||
init_weapon_range_audio_registry();
|
||||
if (@callback is null) return false;
|
||||
if (@callback is null)
|
||||
return false;
|
||||
weapon_range_audio_callbacks.insert_last(callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
int get_current_weapon_range() {
|
||||
if (sling_equipped) return SLING_RANGE;
|
||||
if (bow_equipped) return BOW_RANGE;
|
||||
if (spear_equipped) return 1;
|
||||
if (axe_equipped) return 0;
|
||||
if (sling_equipped)
|
||||
return SLING_RANGE;
|
||||
if (bow_equipped)
|
||||
return BOW_RANGE;
|
||||
if (spear_equipped)
|
||||
return 1;
|
||||
if (axe_equipped)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void play_weapon_range_sound(string sound_file, int creature_pos) {
|
||||
if (!file_exists(sound_file)) return;
|
||||
if (!audio_asset_exists(sound_file))
|
||||
return;
|
||||
// Notification sound: keep centered on the player like footsteps
|
||||
int handle = p.play_stationary(sound_file, false);
|
||||
if (handle != -1) {
|
||||
@@ -36,7 +43,7 @@ void play_weapon_range_sound(string sound_file, int creature_pos) {
|
||||
}
|
||||
}
|
||||
|
||||
void update_weapon_range_audio(int creature_pos, bool &inout was_in_range) {
|
||||
void update_weapon_range_audio(int creature_pos, bool& inout was_in_range) {
|
||||
int range = get_current_weapon_range();
|
||||
bool in_range = (range >= 0) && (abs(creature_pos - x) <= range);
|
||||
if (in_range && !was_in_range) {
|
||||
@@ -47,15 +54,16 @@ void update_weapon_range_audio(int creature_pos, bool &inout was_in_range) {
|
||||
was_in_range = in_range;
|
||||
}
|
||||
|
||||
void force_weapon_range_exit(int creature_pos, bool &inout was_in_range) {
|
||||
if (!was_in_range) return;
|
||||
void force_weapon_range_exit(int creature_pos, bool& inout was_in_range) {
|
||||
if (!was_in_range)
|
||||
return;
|
||||
play_weapon_range_sound("sounds/enemies/exit_range.ogg", creature_pos);
|
||||
was_in_range = false;
|
||||
}
|
||||
|
||||
void update_weapon_range_audio_all() {
|
||||
for (uint i = 0; i < weapon_range_audio_callbacks.length(); i++) {
|
||||
WeaponRangeAudioCallback@ callback = weapon_range_audio_callbacks[i];
|
||||
WeaponRangeAudioCallback @callback = weapon_range_audio_callbacks[i];
|
||||
if (@callback !is null) {
|
||||
callback();
|
||||
}
|
||||
|
||||
+44
-33
@@ -47,7 +47,8 @@ class ThunderStrike {
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (direction == 0) return; // Stationary thunder
|
||||
if (direction == 0)
|
||||
return; // Stationary thunder
|
||||
|
||||
if (movement_timer.elapsed >= movement_speed) {
|
||||
position += direction;
|
||||
@@ -65,23 +66,16 @@ class ThunderStrike {
|
||||
}
|
||||
}
|
||||
|
||||
ThunderStrike@[] active_thunder;
|
||||
ThunderStrike @[] active_thunder;
|
||||
timer thunder_timer;
|
||||
int next_thunder_interval = 0;
|
||||
|
||||
// Sound file paths
|
||||
string[] wind_sounds = {
|
||||
"", // INTENSITY_NONE placeholder
|
||||
"sounds/nature/wind_low.ogg",
|
||||
"sounds/nature/wind_medium.ogg",
|
||||
"sounds/nature/wind_high.ogg"
|
||||
};
|
||||
string[] wind_sounds = {"", // INTENSITY_NONE placeholder
|
||||
"sounds/nature/wind_low.ogg", "sounds/nature/wind_medium.ogg", "sounds/nature/wind_high.ogg"};
|
||||
|
||||
string[] thunder_sounds = {
|
||||
"sounds/nature/thunder_low.ogg",
|
||||
"sounds/nature/thunder_medium.ogg",
|
||||
"sounds/nature/thunder_high.ogg"
|
||||
};
|
||||
string[] thunder_sounds = {"sounds/nature/thunder_low.ogg", "sounds/nature/thunder_medium.ogg",
|
||||
"sounds/nature/thunder_high.ogg"};
|
||||
|
||||
void init_weather() {
|
||||
stop_all_weather_sounds();
|
||||
@@ -236,8 +230,10 @@ void maybe_change_wind_intensity() {
|
||||
if (random(1, 100) <= 30) {
|
||||
int change = random(-1, 1);
|
||||
int new_intensity = wind_intensity + change;
|
||||
if (new_intensity < INTENSITY_LOW) new_intensity = INTENSITY_LOW;
|
||||
if (new_intensity > INTENSITY_HIGH) new_intensity = INTENSITY_HIGH;
|
||||
if (new_intensity < INTENSITY_LOW)
|
||||
new_intensity = INTENSITY_LOW;
|
||||
if (new_intensity > INTENSITY_HIGH)
|
||||
new_intensity = INTENSITY_HIGH;
|
||||
wind_intensity = new_intensity;
|
||||
}
|
||||
}
|
||||
@@ -246,8 +242,10 @@ void maybe_change_rain_intensity() {
|
||||
if (random(1, 100) <= 30) {
|
||||
int change = random(-1, 1);
|
||||
int new_intensity = rain_intensity + change;
|
||||
if (new_intensity < INTENSITY_LOW) new_intensity = INTENSITY_LOW;
|
||||
if (new_intensity > INTENSITY_HIGH) new_intensity = INTENSITY_HIGH;
|
||||
if (new_intensity < INTENSITY_LOW)
|
||||
new_intensity = INTENSITY_LOW;
|
||||
if (new_intensity > INTENSITY_HIGH)
|
||||
new_intensity = INTENSITY_HIGH;
|
||||
if (new_intensity != rain_intensity) {
|
||||
fade_rain_to_intensity(new_intensity);
|
||||
}
|
||||
@@ -258,15 +256,19 @@ void maybe_change_storm_intensity() {
|
||||
// Possibly change wind
|
||||
if (random(1, 100) <= 25) {
|
||||
int new_wind = wind_intensity + random(-1, 1);
|
||||
if (new_wind < INTENSITY_LOW) new_wind = INTENSITY_LOW;
|
||||
if (new_wind > INTENSITY_HIGH) new_wind = INTENSITY_HIGH;
|
||||
if (new_wind < INTENSITY_LOW)
|
||||
new_wind = INTENSITY_LOW;
|
||||
if (new_wind > INTENSITY_HIGH)
|
||||
new_wind = INTENSITY_HIGH;
|
||||
wind_intensity = new_wind;
|
||||
}
|
||||
// Possibly change rain
|
||||
if (random(1, 100) <= 25) {
|
||||
int new_rain = rain_intensity + random(-1, 1);
|
||||
if (new_rain < INTENSITY_LOW) new_rain = INTENSITY_LOW;
|
||||
if (new_rain > INTENSITY_HIGH) new_rain = INTENSITY_HIGH;
|
||||
if (new_rain < INTENSITY_LOW)
|
||||
new_rain = INTENSITY_LOW;
|
||||
if (new_rain > INTENSITY_HIGH)
|
||||
new_rain = INTENSITY_HIGH;
|
||||
if (new_rain != rain_intensity) {
|
||||
fade_rain_to_intensity(new_rain);
|
||||
}
|
||||
@@ -275,7 +277,8 @@ void maybe_change_storm_intensity() {
|
||||
|
||||
// Wind gust implementation
|
||||
void update_wind_gusts() {
|
||||
if (wind_intensity == INTENSITY_NONE) return;
|
||||
if (wind_intensity == INTENSITY_NONE)
|
||||
return;
|
||||
|
||||
// Check if it's time for next gust
|
||||
if (wind_gust_timer.elapsed >= next_wind_gust_delay) {
|
||||
@@ -286,7 +289,8 @@ void update_wind_gusts() {
|
||||
}
|
||||
|
||||
void play_wind_gust() {
|
||||
if (wind_intensity == INTENSITY_NONE || wind_intensity > INTENSITY_HIGH) return;
|
||||
if (wind_intensity == INTENSITY_NONE || wind_intensity > INTENSITY_HIGH)
|
||||
return;
|
||||
|
||||
// Clean up previous wind gust if it's stale
|
||||
if (wind_sound_handle != -1 && !p.sound_is_active(wind_sound_handle)) {
|
||||
@@ -300,14 +304,18 @@ void play_wind_gust() {
|
||||
|
||||
// Rain fade implementation
|
||||
float get_rain_target_volume(int intensity) {
|
||||
if (intensity == INTENSITY_NONE) return WEATHER_MIN_VOLUME;
|
||||
if (intensity == INTENSITY_LOW) return RAIN_VOLUME_LIGHT;
|
||||
if (intensity == INTENSITY_MEDIUM) return RAIN_VOLUME_MODERATE;
|
||||
if (intensity == INTENSITY_NONE)
|
||||
return WEATHER_MIN_VOLUME;
|
||||
if (intensity == INTENSITY_LOW)
|
||||
return RAIN_VOLUME_LIGHT;
|
||||
if (intensity == INTENSITY_MEDIUM)
|
||||
return RAIN_VOLUME_MODERATE;
|
||||
return RAIN_VOLUME_HEAVY;
|
||||
}
|
||||
|
||||
void fade_rain_to_intensity(int new_intensity) {
|
||||
if (new_intensity == rain_intensity && !rain_fading) return;
|
||||
if (new_intensity == rain_intensity && !rain_fading)
|
||||
return;
|
||||
|
||||
// Complete any current fade
|
||||
if (rain_fading) {
|
||||
@@ -341,14 +349,16 @@ void fade_rain_to_intensity(int new_intensity) {
|
||||
}
|
||||
|
||||
void update_rain_fade() {
|
||||
if (!rain_fading) return;
|
||||
if (!rain_fading)
|
||||
return;
|
||||
if (rain_sound_handle == -1) {
|
||||
rain_fading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
float progress = float(rain_fade_timer.elapsed) / float(rain_fade_duration);
|
||||
if (progress > 1.0) progress = 1.0;
|
||||
if (progress > 1.0)
|
||||
progress = 1.0;
|
||||
|
||||
float current_vol = rain_fade_from_volume + ((rain_fade_to_volume - rain_fade_from_volume) * progress);
|
||||
p.update_sound_start_values(rain_sound_handle, 0.0, current_vol, 1.0);
|
||||
@@ -384,7 +394,8 @@ void update_thunder() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!thunder_enabled) return;
|
||||
if (!thunder_enabled)
|
||||
return;
|
||||
|
||||
// Check if it's time for new thunder
|
||||
if (thunder_timer.elapsed >= next_thunder_interval) {
|
||||
@@ -417,7 +428,7 @@ void spawn_thunder() {
|
||||
int handle = play_1d_with_volume_step(thunder_file, x, thunder_pos, false, THUNDER_SOUND_VOLUME_STEP);
|
||||
|
||||
if (handle != -1) {
|
||||
ThunderStrike@ strike = ThunderStrike(thunder_pos, direction, handle, speed);
|
||||
ThunderStrike @strike = ThunderStrike(thunder_pos, direction, handle, speed);
|
||||
active_thunder.insert_last(strike);
|
||||
}
|
||||
} else {
|
||||
@@ -429,7 +440,7 @@ void spawn_thunder() {
|
||||
int handle = play_1d_with_volume_step(thunder_file, x, thunder_pos, false, THUNDER_SOUND_VOLUME_STEP);
|
||||
|
||||
if (handle != -1) {
|
||||
ThunderStrike@ strike = ThunderStrike(thunder_pos, 0, handle, 0);
|
||||
ThunderStrike @strike = ThunderStrike(thunder_pos, 0, handle, 0);
|
||||
active_thunder.insert_last(strike);
|
||||
}
|
||||
}
|
||||
@@ -462,7 +473,7 @@ string serialize_weather() {
|
||||
}
|
||||
|
||||
void deserialize_weather(string data) {
|
||||
string[]@ parts = data.split("|");
|
||||
string[] @parts = data.split("|");
|
||||
if (parts.length() < 4) {
|
||||
init_weather();
|
||||
return;
|
||||
|
||||
+52
-34
@@ -32,8 +32,10 @@ class MountainRange {
|
||||
|
||||
// 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;
|
||||
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
|
||||
@@ -63,7 +65,8 @@ class MountainRange {
|
||||
}
|
||||
|
||||
void midpoint_displace(int left, int right, int roughness) {
|
||||
if (right - left <= 1) return;
|
||||
if (right - left <= 1)
|
||||
return;
|
||||
|
||||
int mid = (left + right) / 2;
|
||||
int avg = (elevations[left] + elevations[right]) / 2;
|
||||
@@ -71,7 +74,8 @@ class MountainRange {
|
||||
elevations[mid] = avg + displacement;
|
||||
|
||||
int new_roughness = roughness * 7 / 10;
|
||||
if (new_roughness < 1) new_roughness = 1;
|
||||
if (new_roughness < 1)
|
||||
new_roughness = 1;
|
||||
|
||||
midpoint_displace(left, mid, new_roughness);
|
||||
midpoint_displace(mid, right, new_roughness);
|
||||
@@ -85,12 +89,12 @@ class MountainRange {
|
||||
iterations++;
|
||||
|
||||
for (int i = 1; i < int(elevations.length()); i++) {
|
||||
int diff = elevations[i] - elevations[i-1];
|
||||
int diff = elevations[i] - elevations[i - 1];
|
||||
if (diff > MOUNTAIN_MAX_SLOPE) {
|
||||
elevations[i] = elevations[i-1] + 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;
|
||||
elevations[i] = elevations[i - 1] - MOUNTAIN_MAX_SLOPE;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -105,7 +109,7 @@ class MountainRange {
|
||||
// Find all steep sections (positions where rope would be needed)
|
||||
int[] steep_positions;
|
||||
for (int i = 1; i < size; i++) {
|
||||
if (abs(elevations[i] - elevations[i-1]) >= MOUNTAIN_STEEP_THRESHOLD) {
|
||||
if (abs(elevations[i] - elevations[i - 1]) >= MOUNTAIN_STEEP_THRESHOLD) {
|
||||
steep_positions.insert_last(i);
|
||||
}
|
||||
}
|
||||
@@ -115,7 +119,8 @@ class MountainRange {
|
||||
int steep_pos = steep_positions[s];
|
||||
|
||||
// Check if we have enough tiles after this steep section for a plateau
|
||||
if (steep_pos + MIN_PLATEAU_TILES >= size) continue;
|
||||
if (steep_pos + MIN_PLATEAU_TILES >= size)
|
||||
continue;
|
||||
|
||||
// Get the elevation after the steep climb
|
||||
int plateau_start_elevation = elevations[steep_pos];
|
||||
@@ -123,7 +128,8 @@ class MountainRange {
|
||||
// Ensure next MIN_PLATEAU_TILES have gentle slopes
|
||||
for (int p = 1; p <= MIN_PLATEAU_TILES; p++) {
|
||||
int tile_idx = steep_pos + p;
|
||||
if (tile_idx >= size) break;
|
||||
if (tile_idx >= size)
|
||||
break;
|
||||
|
||||
// Calculate max allowed elevation change for gentle slope
|
||||
int prev_elevation = elevations[tile_idx - 1];
|
||||
@@ -146,7 +152,8 @@ class MountainRange {
|
||||
|
||||
// Final pass: ensure no negative elevations anywhere
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (elevations[i] < 0) elevations[i] = 0;
|
||||
if (elevations[i] < 0)
|
||||
elevations[i] = 0;
|
||||
}
|
||||
|
||||
// Prefer climbing up before descending by adjusting early terrain
|
||||
@@ -170,15 +177,19 @@ class MountainRange {
|
||||
// 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]) {
|
||||
if (elevations[i] < elevations[i - 1] && elevations[i] < elevations[i + 1] &&
|
||||
elevations[i] < elevations[i - 2] && elevations[i] < elevations[i + 2]) {
|
||||
// Keep mountain streams off both extreme edge tiles.
|
||||
if (i > 0 && i < int(elevations.length()) - 1) {
|
||||
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());
|
||||
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);
|
||||
@@ -193,12 +204,12 @@ class MountainRange {
|
||||
// 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 = abs(elevations[i] - elevations[i-1]);
|
||||
int diff = abs(elevations[i] - elevations[i - 1]);
|
||||
|
||||
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)) {
|
||||
(elevations[i - 1] >= 10 && elevations[i - 1] <= 20)) {
|
||||
has_steep_climb = true;
|
||||
break;
|
||||
}
|
||||
@@ -248,24 +259,26 @@ class MountainRange {
|
||||
|
||||
// Last transition: tile size-2 to tile size-1
|
||||
if (size >= 2) {
|
||||
if (abs(elevations[size-1] - elevations[size-2]) > 20) {
|
||||
if (elevations[size-2] > elevations[size-1]) {
|
||||
elevations[size-2] = elevations[size-1] + 20;
|
||||
if (abs(elevations[size - 1] - elevations[size - 2]) > 20) {
|
||||
if (elevations[size - 2] > elevations[size - 1]) {
|
||||
elevations[size - 2] = elevations[size - 1] + 20;
|
||||
} else {
|
||||
elevations[size-2] = elevations[size-1] - 20;
|
||||
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;
|
||||
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";
|
||||
if (world_x < start_position || world_x > end_position)
|
||||
return "stone";
|
||||
int index = world_x - start_position;
|
||||
return terrain_types[index];
|
||||
}
|
||||
@@ -285,16 +298,19 @@ class MountainRange {
|
||||
}
|
||||
|
||||
bool is_stream_at(int world_x) {
|
||||
if (!contains_position(world_x)) return false;
|
||||
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;
|
||||
if (stream_positions[i] == index)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (stream_positions.length() == 0) return;
|
||||
if (stream_positions.length() == 0)
|
||||
return;
|
||||
|
||||
// Find nearest stream to player
|
||||
int nearest_stream = -1;
|
||||
@@ -336,10 +352,9 @@ class MountainRange {
|
||||
}
|
||||
stream_sound_position = -1;
|
||||
}
|
||||
}
|
||||
MountainRange@[] world_mountains;
|
||||
} MountainRange @[] world_mountains;
|
||||
|
||||
MountainRange@ get_mountain_at(int world_x) {
|
||||
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];
|
||||
@@ -349,21 +364,24 @@ MountainRange@ get_mountain_at(int world_x) {
|
||||
}
|
||||
|
||||
int get_mountain_elevation_at(int world_x) {
|
||||
MountainRange@ mountain = get_mountain_at(world_x);
|
||||
if (mountain is null) return 0;
|
||||
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;
|
||||
MountainRange @mountain = get_mountain_at(world_x);
|
||||
if (mountain is null)
|
||||
return false;
|
||||
return mountain.is_stream_at(world_x);
|
||||
}
|
||||
|
||||
void update_mountains_with_audio_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||
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++) {
|
||||
if (limit_audio && !range_overlaps_active_areas(world_mountains[i].start_position, world_mountains[i].end_position, areaStarts, areaEnds)) {
|
||||
if (limit_audio && !range_overlaps_active_areas(world_mountains[i].start_position,
|
||||
world_mountains[i].end_position, areaStarts, areaEnds)) {
|
||||
world_mountains[i].destroy();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@ class WorldFirepit {
|
||||
WorldFirepit(int pos) {
|
||||
position = pos;
|
||||
}
|
||||
}
|
||||
WorldFirepit@[] world_firepits;
|
||||
} WorldFirepit @[] world_firepits;
|
||||
|
||||
class WorldHerbGarden {
|
||||
int position;
|
||||
@@ -16,8 +15,7 @@ class WorldHerbGarden {
|
||||
WorldHerbGarden(int pos) {
|
||||
position = pos;
|
||||
}
|
||||
}
|
||||
WorldHerbGarden@[] world_herb_gardens;
|
||||
} WorldHerbGarden @[] world_herb_gardens;
|
||||
|
||||
class WorldStorage {
|
||||
int position;
|
||||
@@ -25,8 +23,7 @@ class WorldStorage {
|
||||
WorldStorage(int pos) {
|
||||
position = pos;
|
||||
}
|
||||
}
|
||||
WorldStorage@[] world_storages;
|
||||
} WorldStorage @[] world_storages;
|
||||
|
||||
class WorldPasture {
|
||||
int position;
|
||||
@@ -34,8 +31,7 @@ class WorldPasture {
|
||||
WorldPasture(int pos) {
|
||||
position = pos;
|
||||
}
|
||||
}
|
||||
WorldPasture@[] world_pastures;
|
||||
} WorldPasture @[] world_pastures;
|
||||
|
||||
class WorldStable {
|
||||
int position;
|
||||
@@ -43,8 +39,7 @@ class WorldStable {
|
||||
WorldStable(int pos) {
|
||||
position = pos;
|
||||
}
|
||||
}
|
||||
WorldStable@[] world_stables;
|
||||
} WorldStable @[] world_stables;
|
||||
|
||||
class WorldAltar {
|
||||
int position;
|
||||
@@ -52,8 +47,7 @@ class WorldAltar {
|
||||
WorldAltar(int pos) {
|
||||
position = pos;
|
||||
}
|
||||
}
|
||||
WorldAltar@[] world_altars;
|
||||
} WorldAltar @[] world_altars;
|
||||
|
||||
int horses_count = 0;
|
||||
int livestock_count = 0;
|
||||
@@ -61,17 +55,17 @@ int storage_level = STORAGE_LEVEL_BASE;
|
||||
|
||||
// Add functions
|
||||
void add_world_firepit(int pos) {
|
||||
WorldFirepit@ fp = WorldFirepit(pos);
|
||||
WorldFirepit @fp = WorldFirepit(pos);
|
||||
world_firepits.insert_last(fp);
|
||||
}
|
||||
|
||||
void add_world_herb_garden(int pos) {
|
||||
WorldHerbGarden@ hg = WorldHerbGarden(pos);
|
||||
WorldHerbGarden @hg = WorldHerbGarden(pos);
|
||||
world_herb_gardens.insert_last(hg);
|
||||
}
|
||||
|
||||
void add_world_storage(int pos) {
|
||||
WorldStorage@ s = WorldStorage(pos);
|
||||
WorldStorage @s = WorldStorage(pos);
|
||||
world_storages.insert_last(s);
|
||||
}
|
||||
|
||||
@@ -82,22 +76,22 @@ void ensure_base_storage() {
|
||||
}
|
||||
|
||||
void add_world_pasture(int pos) {
|
||||
WorldPasture@ p = WorldPasture(pos);
|
||||
WorldPasture @p = WorldPasture(pos);
|
||||
world_pastures.insert_last(p);
|
||||
}
|
||||
|
||||
void add_world_stable(int pos) {
|
||||
WorldStable@ s = WorldStable(pos);
|
||||
WorldStable @s = WorldStable(pos);
|
||||
world_stables.insert_last(s);
|
||||
}
|
||||
|
||||
void add_world_altar(int pos) {
|
||||
WorldAltar@ a = WorldAltar(pos);
|
||||
WorldAltar @a = WorldAltar(pos);
|
||||
world_altars.insert_last(a);
|
||||
}
|
||||
|
||||
// Getter functions
|
||||
WorldFirepit@ get_firepit_at(int pos) {
|
||||
WorldFirepit @get_firepit_at(int pos) {
|
||||
for (uint i = 0; i < world_firepits.length(); i++) {
|
||||
if (world_firepits[i].position == pos) {
|
||||
return @world_firepits[i];
|
||||
@@ -106,10 +100,10 @@ WorldFirepit@ get_firepit_at(int pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldFirepit@ get_firepit_near(int pos, int range) {
|
||||
WorldFirepit @get_firepit_near(int pos, int range) {
|
||||
// Check for firepit within specified range
|
||||
for (int check_x = pos - range; check_x <= pos + range; check_x++) {
|
||||
WorldFirepit@ firepit = get_firepit_at(check_x);
|
||||
WorldFirepit @firepit = get_firepit_at(check_x);
|
||||
if (firepit != null) {
|
||||
return @firepit;
|
||||
}
|
||||
@@ -117,7 +111,7 @@ WorldFirepit@ get_firepit_near(int pos, int range) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldHerbGarden@ get_herb_garden_at(int pos) {
|
||||
WorldHerbGarden @get_herb_garden_at(int pos) {
|
||||
for (uint i = 0; i < world_herb_gardens.length(); i++) {
|
||||
if (world_herb_gardens[i].position == pos) {
|
||||
return @world_herb_gardens[i];
|
||||
@@ -126,7 +120,7 @@ WorldHerbGarden@ get_herb_garden_at(int pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldHerbGarden@ get_herb_garden_at_base() {
|
||||
WorldHerbGarden @get_herb_garden_at_base() {
|
||||
// Check if herb garden exists anywhere in base area (0-4)
|
||||
for (uint i = 0; i < world_herb_gardens.length(); i++) {
|
||||
if (world_herb_gardens[i].position <= BASE_END) {
|
||||
@@ -136,7 +130,7 @@ WorldHerbGarden@ get_herb_garden_at_base() {
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldStorage@ get_storage_at(int pos) {
|
||||
WorldStorage @get_storage_at(int pos) {
|
||||
for (uint i = 0; i < world_storages.length(); i++) {
|
||||
if (world_storages[i].position == pos) {
|
||||
return @world_storages[i];
|
||||
@@ -145,7 +139,7 @@ WorldStorage@ get_storage_at(int pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldPasture@ get_pasture_at(int pos) {
|
||||
WorldPasture @get_pasture_at(int pos) {
|
||||
for (uint i = 0; i < world_pastures.length(); i++) {
|
||||
if (world_pastures[i].position == pos) {
|
||||
return @world_pastures[i];
|
||||
@@ -154,7 +148,7 @@ WorldPasture@ get_pasture_at(int pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldStable@ get_stable_at(int pos) {
|
||||
WorldStable @get_stable_at(int pos) {
|
||||
for (uint i = 0; i < world_stables.length(); i++) {
|
||||
if (world_stables[i].position == pos) {
|
||||
return @world_stables[i];
|
||||
@@ -163,7 +157,7 @@ WorldStable@ get_stable_at(int pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldAltar@ get_altar_at(int pos) {
|
||||
WorldAltar @get_altar_at(int pos) {
|
||||
for (uint i = 0; i < world_altars.length(); i++) {
|
||||
if (world_altars[i].position == pos) {
|
||||
return @world_altars[i];
|
||||
|
||||
@@ -40,11 +40,10 @@ class WorldDrop {
|
||||
sound_handle = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
WorldDrop@[] world_drops;
|
||||
} WorldDrop @[] world_drops;
|
||||
|
||||
void add_world_drop(int pos, string type) {
|
||||
WorldDrop@ d = WorldDrop(pos, type);
|
||||
WorldDrop @d = WorldDrop(pos, type);
|
||||
world_drops.insert_last(d);
|
||||
}
|
||||
|
||||
@@ -55,7 +54,8 @@ void update_world_drops() {
|
||||
bool limit_audio = (areaStarts.length() > 0);
|
||||
|
||||
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)) {
|
||||
if (limit_audio &&
|
||||
!range_overlaps_active_areas(world_drops[i].position, world_drops[i].position, areaStarts, areaEnds)) {
|
||||
world_drops[i].destroy();
|
||||
continue;
|
||||
}
|
||||
@@ -63,7 +63,7 @@ void update_world_drops() {
|
||||
}
|
||||
}
|
||||
|
||||
WorldDrop@ get_drop_at(int pos) {
|
||||
WorldDrop @get_drop_at(int pos) {
|
||||
for (uint i = 0; i < world_drops.length(); i++) {
|
||||
if (world_drops[i].position == pos) {
|
||||
return @world_drops[i];
|
||||
@@ -100,7 +100,7 @@ bool try_pickup_small_game(string game_type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_pickup_world_drop(WorldDrop@ drop) {
|
||||
bool try_pickup_world_drop(WorldDrop @drop) {
|
||||
if (get_flying_creature_config_by_drop_type(drop.type) !is null) {
|
||||
return try_pickup_small_game(drop.type);
|
||||
}
|
||||
|
||||
@@ -78,11 +78,10 @@ class WorldFire {
|
||||
sound_handle = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
WorldFire@[] world_fires;
|
||||
} WorldFire @[] world_fires;
|
||||
|
||||
void add_world_fire(int pos) {
|
||||
WorldFire@ f = WorldFire(pos);
|
||||
WorldFire @f = WorldFire(pos);
|
||||
world_fires.insert_last(f);
|
||||
}
|
||||
|
||||
@@ -95,7 +94,8 @@ void update_fires() {
|
||||
// Update all fires and remove any that have burned out
|
||||
for (uint i = 0; i < world_fires.length(); i++) {
|
||||
world_fires[i].update();
|
||||
if (limit_audio && !range_overlaps_active_areas(world_fires[i].position, world_fires[i].position, areaStarts, areaEnds)) {
|
||||
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;
|
||||
@@ -113,7 +113,7 @@ void update_fires() {
|
||||
}
|
||||
}
|
||||
|
||||
WorldFire@ get_fire_at(int pos) {
|
||||
WorldFire @get_fire_at(int pos) {
|
||||
for (uint i = 0; i < world_fires.length(); i++) {
|
||||
if (world_fires[i].position == pos) {
|
||||
return @world_fires[i];
|
||||
@@ -122,10 +122,10 @@ WorldFire@ get_fire_at(int pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldFire@ get_fire_near(int pos) {
|
||||
WorldFire @get_fire_near(int pos) {
|
||||
// Check for fire at current position or adjacent tiles
|
||||
for (int check_x = pos - 1; check_x <= pos + 1; check_x++) {
|
||||
WorldFire@ fire = get_fire_at(check_x);
|
||||
WorldFire @fire = get_fire_at(check_x);
|
||||
if (fire != null && fire.is_burning()) {
|
||||
return @fire;
|
||||
}
|
||||
@@ -133,10 +133,10 @@ WorldFire@ get_fire_near(int pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldFire@ get_fire_within_range(int pos, int range) {
|
||||
WorldFire @get_fire_within_range(int pos, int range) {
|
||||
// Check for fire within specified range
|
||||
for (int check_x = pos - range; check_x <= pos + range; check_x++) {
|
||||
WorldFire@ fire = get_fire_at(check_x);
|
||||
WorldFire @fire = get_fire_at(check_x);
|
||||
if (fire != null && fire.is_burning()) {
|
||||
return @fire;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,8 @@ class WorldSnare {
|
||||
}
|
||||
sound_handle = p.play_1d("sounds/actions/set_snare.ogg", x, position, true);
|
||||
if (sound_handle != -1) {
|
||||
p.update_sound_positioning_values(sound_handle, SNARE_SOUND_PAN_STEP, SNARE_SOUND_VOLUME_STEP, true);
|
||||
p.update_sound_positioning_values(sound_handle, SNARE_SOUND_PAN_STEP, SNARE_SOUND_VOLUME_STEP,
|
||||
true);
|
||||
}
|
||||
}
|
||||
} else if (sound_handle != -1) {
|
||||
@@ -71,7 +72,8 @@ class WorldSnare {
|
||||
// After that: escape chance increases by 2% per game hour
|
||||
if (hours_with_catch > 1) {
|
||||
escape_chance = (hours_with_catch - 1) * 2;
|
||||
if (escape_chance > 95) escape_chance = 95;
|
||||
if (escape_chance > 95)
|
||||
escape_chance = 95;
|
||||
|
||||
int roll = random(1, 100);
|
||||
if (roll <= escape_chance) {
|
||||
@@ -83,7 +85,8 @@ class WorldSnare {
|
||||
}
|
||||
} else {
|
||||
// Trying to catch small game
|
||||
if (catch_chance < 75) catch_chance += 5;
|
||||
if (catch_chance < 75)
|
||||
catch_chance += 5;
|
||||
|
||||
int roll = random(1, 100);
|
||||
if (roll <= catch_chance) {
|
||||
@@ -104,15 +107,14 @@ class WorldSnare {
|
||||
sound_handle = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
WorldSnare@[] world_snares;
|
||||
} WorldSnare @[] world_snares;
|
||||
|
||||
void add_world_snare(int pos) {
|
||||
WorldSnare@ s = WorldSnare(pos);
|
||||
WorldSnare @s = WorldSnare(pos);
|
||||
world_snares.insert_last(s);
|
||||
}
|
||||
|
||||
WorldSnare@ get_snare_at(int pos) {
|
||||
WorldSnare @get_snare_at(int pos) {
|
||||
for (uint i = 0; i < world_snares.length(); i++) {
|
||||
if (world_snares[i].position == pos) {
|
||||
return @world_snares[i];
|
||||
@@ -133,7 +135,7 @@ void remove_snare_at(int pos) {
|
||||
|
||||
// Called when player moves onto a tile
|
||||
void check_snare_collision(int player_x) {
|
||||
WorldSnare@ s = get_snare_at(player_x);
|
||||
WorldSnare @s = get_snare_at(player_x);
|
||||
if (s != null && s.active) {
|
||||
// Break the snare
|
||||
p.play_stationary("sounds/actions/break_snare.ogg", false);
|
||||
@@ -155,7 +157,7 @@ void update_snares() {
|
||||
bool limit_audio = (areaStarts.length() > 0);
|
||||
|
||||
for (int i = int(world_snares.length()) - 1; i >= 0; i--) {
|
||||
WorldSnare@ snare = world_snares[i];
|
||||
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) {
|
||||
|
||||
@@ -63,8 +63,7 @@ class WorldStream {
|
||||
}
|
||||
sound_position = -1;
|
||||
}
|
||||
}
|
||||
WorldStream@[] world_streams;
|
||||
} WorldStream @[] world_streams;
|
||||
|
||||
string get_expanded_area_type(int index) {
|
||||
string terrain = expanded_terrain_types[index];
|
||||
@@ -74,7 +73,7 @@ string get_expanded_area_type(int index) {
|
||||
return terrain;
|
||||
}
|
||||
|
||||
bool get_audio_area_bounds_for_position(int pos, int &out areaStart, int &out areaEnd) {
|
||||
bool get_audio_area_bounds_for_position(int pos, int& out areaStart, int& out areaEnd) {
|
||||
if (pos <= BASE_END) {
|
||||
areaStart = 0;
|
||||
areaEnd = BASE_END;
|
||||
@@ -97,18 +96,21 @@ bool get_audio_area_bounds_for_position(int pos, int &out areaStart, int &out ar
|
||||
|
||||
int index = pos - expanded_area_start;
|
||||
int total = int(expanded_terrain_types.length());
|
||||
if (index < 0 || index >= total) return false;
|
||||
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;
|
||||
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;
|
||||
if (get_expanded_area_type(right + 1) != areaType)
|
||||
break;
|
||||
right++;
|
||||
}
|
||||
|
||||
@@ -117,13 +119,14 @@ bool get_audio_area_bounds_for_position(int pos, int &out areaStart, int &out ar
|
||||
return true;
|
||||
}
|
||||
|
||||
void get_active_audio_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||
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;
|
||||
if (!get_audio_area_bounds_for_position(x, currentStart, currentEnd))
|
||||
return;
|
||||
|
||||
areaStarts.insert_last(currentStart);
|
||||
areaEnds.insert_last(currentEnd);
|
||||
@@ -151,7 +154,7 @@ void get_active_audio_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||
}
|
||||
}
|
||||
|
||||
bool range_overlaps_active_areas(int rangeStart, int rangeEnd, int[]@ areaStarts, int[]@ areaEnds) {
|
||||
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;
|
||||
@@ -161,7 +164,7 @@ bool range_overlaps_active_areas(int rangeStart, int rangeEnd, int[]@ areaStarts
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -172,7 +175,8 @@ void update_streams() {
|
||||
bool limit_audio = areaStarts.length() > 0;
|
||||
|
||||
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)) {
|
||||
if (limit_audio && !range_overlaps_active_areas(world_streams[i].start_position, world_streams[i].end_position,
|
||||
areaStarts, areaEnds)) {
|
||||
world_streams[i].destroy();
|
||||
continue;
|
||||
}
|
||||
@@ -182,7 +186,7 @@ void update_streams() {
|
||||
update_mountains_with_audio_areas(areaStarts, areaEnds);
|
||||
}
|
||||
|
||||
WorldStream@ get_stream_at(int pos) {
|
||||
WorldStream @get_stream_at(int pos) {
|
||||
for (uint i = 0; i < world_streams.length(); i++) {
|
||||
if (world_streams[i].contains_position(pos)) {
|
||||
return @world_streams[i];
|
||||
@@ -196,7 +200,8 @@ bool is_position_in_water(int pos) {
|
||||
}
|
||||
|
||||
bool is_deep_stream_at(int pos) {
|
||||
WorldStream@ stream = get_stream_at(pos);
|
||||
if (stream == null) return false;
|
||||
WorldStream @stream = get_stream_at(pos);
|
||||
if (stream == null)
|
||||
return false;
|
||||
return stream.get_width() > 3;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user