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);
|
||||
}
|
||||
}
|
||||
|
||||
+244
-147
@@ -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,9 +1070,8 @@ 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."
|
||||
: baskets_broken + " baskets 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,12 +23,12 @@ 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;
|
||||
int[] adventure_ids; // 1 = Unicorn, 2 = Bandit's Hideout
|
||||
|
||||
|
||||
if (mountain !is null) {
|
||||
// Mountain terrain
|
||||
options.insert_last("Unicorn Hunt (Mountain Boss)");
|
||||
@@ -39,40 +39,42 @@ void run_adventure_menu(int player_x) {
|
||||
options.insert_last("Bandit's Hideout");
|
||||
adventure_ids.insert_last(ADVENTURE_BANDIT_HIDEOUT);
|
||||
}
|
||||
|
||||
|
||||
if (options.length() == 0) {
|
||||
speak_with_history("No adventures found in this area.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Show Menu
|
||||
speak_with_history("Adventure Menu.", true);
|
||||
int selection = 0;
|
||||
speak_with_history(options[selection], true);
|
||||
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
handle_global_volume_keys();
|
||||
|
||||
|
||||
if (key_pressed(KEY_ESCAPE)) {
|
||||
speak_with_history("Closed.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
start_adventure(adventure_ids[selection]);
|
||||
|
||||
+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 {
|
||||
|
||||
@@ -10,11 +10,11 @@ class UnicornBoss {
|
||||
timer move_timer;
|
||||
int sound_handle;
|
||||
bool on_bridge;
|
||||
|
||||
|
||||
UnicornBoss() {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
void reset() {
|
||||
health = 450;
|
||||
speed = UNICORN_SPEED;
|
||||
@@ -32,7 +32,7 @@ const int BRIDGE_START = 45;
|
||||
const int BRIDGE_END = 54;
|
||||
const int BRIDGE_SUPPORT_MAX_HEALTH = 100;
|
||||
const float UNICORN_SOUND_VOLUME_STEP = 2.5; // Lower = audible from further away
|
||||
const int UNICORN_SPEED = 80; // ms per tile, 100 tiles * 80ms = 8 seconds per charge
|
||||
const int UNICORN_SPEED = 80; // ms per tile, 100 tiles * 80ms = 8 seconds per charge
|
||||
const bool UNICORN_BOW_CAN_DAMAGE_SUPPORTS = false;
|
||||
const bool UNICORN_SLING_CAN_DAMAGE_SUPPORTS = false;
|
||||
|
||||
@@ -44,7 +44,7 @@ bool player_arena_jumping = false;
|
||||
timer arena_jump_timer;
|
||||
timer arena_walk_timer;
|
||||
timer arena_attack_timer;
|
||||
int player_arena_facing = 1; // 0 = west, 1 = east
|
||||
int player_arena_facing = 1; // 0 = west, 1 = east
|
||||
int[] bridge_supports_health; // 2 supports: Left (start) and Right (end)
|
||||
bool bridge_collapsed = false;
|
||||
string current_unicorn_sound = "";
|
||||
@@ -168,13 +168,15 @@ 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);
|
||||
}
|
||||
|
||||
handle_player_movement();
|
||||
handle_player_actions();
|
||||
|
||||
|
||||
// Updates
|
||||
update_player_jump();
|
||||
update_unicorn();
|
||||
@@ -182,7 +184,7 @@ void run_unicorn_adventure() {
|
||||
update_unicorn_weapon_range_audio();
|
||||
update_pet_adventure_position(player_arena_x);
|
||||
update_pets();
|
||||
|
||||
|
||||
// Check Conditions - unicorn falls when on collapsed bridge
|
||||
if (!unicorn_defeated && bridge_collapsed && unicorn.x >= BRIDGE_START && unicorn.x <= BRIDGE_END) {
|
||||
mark_unicorn_defeated(true);
|
||||
@@ -202,14 +204,14 @@ void run_unicorn_adventure() {
|
||||
give_unicorn_rewards();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (player_health <= 0) {
|
||||
cleanup_unicorn_adventure();
|
||||
speak_with_history("The Unicorn trampled you.", true);
|
||||
// Player death will be handled by main game loop checking player_health <= 0
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Audio
|
||||
p.update_listener_1d(player_arena_x);
|
||||
update_unicorn_audio();
|
||||
@@ -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;
|
||||
}
|
||||
@@ -548,7 +570,7 @@ void check_bridge_collapse() {
|
||||
void update_unicorn() {
|
||||
if (unicorn.move_timer.elapsed >= unicorn.speed) {
|
||||
unicorn.move_timer.restart();
|
||||
|
||||
|
||||
// Move
|
||||
if (unicorn.facing == 1) {
|
||||
unicorn.x++;
|
||||
@@ -563,14 +585,14 @@ void update_unicorn() {
|
||||
unicorn.x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Bridge Logic
|
||||
if (unicorn.x >= BRIDGE_START && unicorn.x <= BRIDGE_END && !bridge_collapsed) {
|
||||
unicorn.on_bridge = true;
|
||||
} else {
|
||||
unicorn.on_bridge = false;
|
||||
}
|
||||
|
||||
|
||||
// Collision with Player
|
||||
if (unicorn.x == player_arena_x && player_arena_y == 0) {
|
||||
player_health -= 10;
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+54
-48
@@ -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);
|
||||
}
|
||||
@@ -160,7 +162,7 @@ void hit_tree_with_spear(int target_x) {
|
||||
|
||||
void update_sling_charge() {
|
||||
int elapsed = sling_charge_timer.elapsed;
|
||||
int cycle_time = 1500; // 1.5 seconds
|
||||
int cycle_time = 1500; // 1.5 seconds
|
||||
int stage_duration = 500; // 0.5 seconds per stage
|
||||
|
||||
// Loop the charge cycle
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+39
-38
@@ -1,14 +1,14 @@
|
||||
// Map configuration
|
||||
int MAP_SIZE = 35;
|
||||
const int BASE_END = 4; // 0-4
|
||||
const int GRASS_END = 19; // 5-19
|
||||
const int BASE_END = 4; // 0-4
|
||||
const int GRASS_END = 19; // 5-19
|
||||
const int GRAVEL_START = 20; // 20-34
|
||||
const int GRAVEL_END = 34; // 20-34
|
||||
const int GRAVEL_END = 34; // 20-34
|
||||
|
||||
// Expansion configuration
|
||||
const int EXPANSION_SIZE = 30;
|
||||
const int EXPANSION_CHANCE = 30; // 30% chance per hour before noon
|
||||
int expanded_area_start = -1; // -1 means not expanded yet
|
||||
int expanded_area_start = -1; // -1 means not expanded yet
|
||||
int expanded_area_end = -1;
|
||||
|
||||
// Movement configuration
|
||||
@@ -193,28 +193,28 @@ const float MASTER_VOLUME_MAX_DB = 0.0;
|
||||
const float MASTER_VOLUME_MIN_DB = -60.0;
|
||||
const float MASTER_VOLUME_STEP_DB = 3.0;
|
||||
const int SNARE_SOUND_RANGE = 2;
|
||||
const float SNARE_SOUND_VOLUME_STEP = 4.0; // More audible for locating snares
|
||||
const float SNARE_SOUND_PAN_STEP = 4.0; // Stronger pan for direction
|
||||
const float SNARE_SOUND_VOLUME_STEP = 4.0; // More audible for locating snares
|
||||
const float SNARE_SOUND_PAN_STEP = 4.0; // Stronger pan for direction
|
||||
const int SNARE_COLLECT_RANGE = 1;
|
||||
|
||||
const int FIRE_SOUND_RANGE = 3;
|
||||
const float FIRE_SOUND_VOLUME_STEP = 5.0; // 15 dB over 3 tiles (FIRE_SOUND_RANGE)
|
||||
const float FIRE_SOUND_VOLUME_STEP = 5.0; // 15 dB over 3 tiles (FIRE_SOUND_RANGE)
|
||||
|
||||
const int FIREPIT_SOUND_RANGE = 5;
|
||||
const float FIREPIT_SOUND_VOLUME_STEP = 6.0; // 30 dB over 5 tiles
|
||||
const float FIREPIT_SOUND_VOLUME_STEP = 6.0; // 30 dB over 5 tiles
|
||||
|
||||
const int STREAM_SOUND_RANGE = 7;
|
||||
const float STREAM_SOUND_VOLUME_STEP = 4.3; // 30 dB over 7 tiles
|
||||
const float STREAM_SOUND_VOLUME_STEP = 4.3; // 30 dB over 7 tiles
|
||||
|
||||
const float TREE_SOUND_VOLUME_STEP = 4.0; // Similar to snares for good audibility
|
||||
const float TREE_SOUND_VOLUME_STEP = 4.0; // Similar to snares for good audibility
|
||||
const int TREE_SOUND_RANGE = 4;
|
||||
const int TREE_MIN_DISTANCE = 10;
|
||||
const int TREE_MAX_PER_AREA = 2;
|
||||
const int TREE_AVOID_STEEP_CLIMB_RANGE = 3;
|
||||
|
||||
const float RESIDENT_DEFENSE_VOLUME_STEP = 3.0; // Default volume for resident counter-attacks
|
||||
const float RESIDENT_DEFENSE_VOLUME_STEP = 3.0; // Default volume for resident counter-attacks
|
||||
const float PLAYER_WEAPON_SOUND_VOLUME_STEP = 3.0;
|
||||
const int FLYING_CREATURE_FADE_OUT_DURATION = 1500; // ms
|
||||
const int FLYING_CREATURE_FADE_OUT_DURATION = 1500; // ms
|
||||
const float FLYING_CREATURE_FADE_OUT_MIN_VOLUME = -40.0; // dB
|
||||
|
||||
// Mountain configuration
|
||||
@@ -225,7 +225,7 @@ const int MOUNTAIN_STEEP_THRESHOLD = 7;
|
||||
const int MOUNTAIN_MAX_SLOPE = 20;
|
||||
const int ROPE_CLIMB_SPEED = 1000;
|
||||
const int MOUNTAIN_STREAM_SOUND_RANGE = 7;
|
||||
const float MOUNTAIN_STREAM_VOLUME_STEP = 4.3; // 30 dB over 7 tiles
|
||||
const float MOUNTAIN_STREAM_VOLUME_STEP = 4.3; // 30 dB over 7 tiles
|
||||
const int QUEST_MAX_ACTIVE = 4;
|
||||
const int QUEST_CHANCE_PER_FAVOR = 10;
|
||||
const int QUEST_MIN_CHANCE = 5;
|
||||
@@ -235,20 +235,20 @@ const int QUEST_LOG_SCORE = 10;
|
||||
const int QUEST_SKIN_SCORE = 14;
|
||||
|
||||
// Resident settings
|
||||
const int MAX_RESIDENTS = 4; // Max residents per base (+ player = 5 total)
|
||||
const int MAX_RESIDENTS = 4; // Max residents per base (+ player = 5 total)
|
||||
const int RESIDENT_WEAPON_BREAK_CHANCE = 10;
|
||||
const int RESIDENT_SPEAR_DAMAGE = 2;
|
||||
const int RESIDENT_SLING_DAMAGE_MIN = 3;
|
||||
const int RESIDENT_SLING_DAMAGE_MAX = 5;
|
||||
const int RESIDENT_BOW_DAMAGE_MIN = 4;
|
||||
const int RESIDENT_BOW_DAMAGE_MAX = 6;
|
||||
const int RESIDENT_COMBAT_BASE_COOLDOWN = 3200; // Base attack delay (2x player axe)
|
||||
const int RESIDENT_COMBAT_TARGET_COOLDOWN = 1600; // At max horses, about player axe speed
|
||||
const int RESIDENT_SNARE_ESCAPE_CHANCE = 5; // 5% chance game escapes when resident retrieves
|
||||
const int RESIDENT_SNARE_CHECK_CHANCE = 15; // 15% chance per hour to check snares
|
||||
const int RESIDENT_FISHING_CHANCE = 6; // 6% chance per resident per hour to catch a fish
|
||||
const int RESIDENT_SMOKE_FISH_CHANCE = 10; // 10% chance per hour to smoke a stored fish
|
||||
const int RESIDENT_TOOL_BREAK_CHANCE = 2; // 2% chance tools break during resident use (fishing poles, knives, baskets)
|
||||
const int RESIDENT_COMBAT_BASE_COOLDOWN = 3200; // Base attack delay (2x player axe)
|
||||
const int RESIDENT_COMBAT_TARGET_COOLDOWN = 1600; // At max horses, about player axe speed
|
||||
const int RESIDENT_SNARE_ESCAPE_CHANCE = 5; // 5% chance game escapes when resident retrieves
|
||||
const int RESIDENT_SNARE_CHECK_CHANCE = 15; // 15% chance per hour to check snares
|
||||
const int RESIDENT_FISHING_CHANCE = 6; // 6% chance per resident per hour to catch a fish
|
||||
const int RESIDENT_SMOKE_FISH_CHANCE = 10; // 10% chance per hour to smoke a stored fish
|
||||
const int RESIDENT_TOOL_BREAK_CHANCE = 2; // 2% chance tools break during resident use (fishing poles, knives, baskets)
|
||||
const int RESIDENT_CLOTHING_REPAIR_COST = 5;
|
||||
const float PLAYER_ITEM_BREAK_CHANCE_MIN = 1.0;
|
||||
const float PLAYER_ITEM_BREAK_CHANCE_MAX = 100.0;
|
||||
@@ -266,8 +266,8 @@ const int PET_LOYALTY_MAX = 10;
|
||||
const int PET_ATTACK_COOLDOWN = 1600; // Same as axe
|
||||
const int PET_RETRIEVE_COOLDOWN = 1000;
|
||||
const int PET_RANDOM_FIND_CHANCE = 20; // Percent per hour when loyalty is high
|
||||
const int PET_ADVENTURE_CHANCE = 5; // Percent chance after adventure victory
|
||||
const int PET_TREE_HAWK_CHANCE = 10; // Percent chance after reaching top of a tree
|
||||
const int PET_ADVENTURE_CHANCE = 5; // Percent chance after adventure victory
|
||||
const int PET_TREE_HAWK_CHANCE = 10; // Percent chance after reaching top of a tree
|
||||
const int PET_LOYALTY_BONUS_THRESHOLD = 5;
|
||||
const int PET_TRAVEL_MIN_MS = 100;
|
||||
const int PET_RANGE = BOW_RANGE + 2;
|
||||
@@ -277,18 +277,19 @@ 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;
|
||||
const int GOOSE_MOVE_INTERVAL_MIN = 800; // Faster movement
|
||||
const int GOOSE_MOVE_INTERVAL_MIN = 800; // Faster movement
|
||||
const int GOOSE_MOVE_INTERVAL_MAX = 2000;
|
||||
const int GOOSE_FLYING_HEIGHT_MIN = 10;
|
||||
const int GOOSE_FLYING_HEIGHT_MAX = 30;
|
||||
const float GOOSE_SOUND_VOLUME_STEP = 3.0;
|
||||
const int GOOSE_FLIGHT_SOUND_DELAY_MIN = 2000; // Honk more often
|
||||
const int GOOSE_FLIGHT_SOUND_DELAY_MAX = 5000;
|
||||
const int GOOSE_FALL_SPEED = 100; // ms per foot
|
||||
const int GOOSE_FLY_AWAY_CHANCE = 0; // Chance out of 1000 per tick to fly away
|
||||
const int GOOSE_FALL_SPEED = 100; // ms per foot
|
||||
const int GOOSE_FLY_AWAY_CHANCE = 0; // Chance out of 1000 per tick to fly away
|
||||
const int GOOSE_MAX_DIST_FROM_WATER = 4; // How far they can wander from water
|
||||
const int GOOSE_MAX_COUNT = 3;
|
||||
const int GOOSE_HOURLY_SPAWN_CHANCE = 40; // Percent chance per hour to spawn a goose
|
||||
@@ -303,28 +304,28 @@ const int TURKEY_FLYING_HEIGHT_MAX = 30;
|
||||
const float TURKEY_SOUND_VOLUME_STEP = 3.0;
|
||||
const int TURKEY_FLIGHT_SOUND_DELAY_MIN = 2000;
|
||||
const int TURKEY_FLIGHT_SOUND_DELAY_MAX = 5000;
|
||||
const int TURKEY_FALL_SPEED = 100; // ms per foot
|
||||
const int TURKEY_FLY_AWAY_CHANCE = 0; // Chance out of 1000 per tick to fly away
|
||||
const int TURKEY_FALL_SPEED = 100; // ms per foot
|
||||
const int TURKEY_FLY_AWAY_CHANCE = 0; // Chance out of 1000 per tick to fly away
|
||||
const int TURKEY_MAX_DIST_FROM_FOREST = 0; // How far they can wander from forest
|
||||
const int TURKEY_MAX_COUNT = 3;
|
||||
const int TURKEY_HOURLY_SPAWN_CHANCE = 40; // Percent chance per hour to spawn a turkey
|
||||
const int TURKEY_SIGHT_RANGE = 0;
|
||||
|
||||
// Weather settings
|
||||
const int WEATHER_FADE_DURATION = 8000; // 8 seconds for smooth audio transitions
|
||||
const int WEATHER_FADE_DURATION = 8000; // 8 seconds for smooth audio transitions
|
||||
const float WEATHER_MIN_VOLUME = -30.0;
|
||||
const float WEATHER_MAX_VOLUME = 0.0;
|
||||
const float RAIN_VOLUME_LIGHT = -18.0;
|
||||
const float RAIN_VOLUME_MODERATE = -10.0;
|
||||
const float RAIN_VOLUME_HEAVY = -3.0;
|
||||
const int WIND_GUST_MIN_DELAY = 30000; // Min 30 seconds between gusts
|
||||
const int WIND_GUST_MAX_DELAY = 60000; // Max 60 seconds between gusts
|
||||
const int THUNDER_MIN_INTERVAL = 8000; // Min 8 seconds between thunder
|
||||
const int THUNDER_MAX_INTERVAL = 35000; // Max 35 seconds between thunder
|
||||
const int THUNDER_MOVEMENT_SPEED = 250; // ms per tile movement (faster roll across sky)
|
||||
const float THUNDER_SOUND_VOLUME_STEP = 0.5; // Gentler volume falloff
|
||||
const int THUNDER_SPAWN_DISTANCE_MIN = 0; // Min distance from player
|
||||
const int THUNDER_SPAWN_DISTANCE_MAX = 20; // Max distance from player
|
||||
const int WIND_GUST_MIN_DELAY = 30000; // Min 30 seconds between gusts
|
||||
const int WIND_GUST_MAX_DELAY = 60000; // Max 60 seconds between gusts
|
||||
const int THUNDER_MIN_INTERVAL = 8000; // Min 8 seconds between thunder
|
||||
const int THUNDER_MAX_INTERVAL = 35000; // Max 35 seconds between thunder
|
||||
const int THUNDER_MOVEMENT_SPEED = 250; // ms per tile movement (faster roll across sky)
|
||||
const float THUNDER_SOUND_VOLUME_STEP = 0.5; // Gentler volume falloff
|
||||
const int THUNDER_SPAWN_DISTANCE_MIN = 0; // Min distance from player
|
||||
const int THUNDER_SPAWN_DISTANCE_MAX = 20; // Max distance from player
|
||||
const int CHANCE_CLEAR_TO_WINDY = 15;
|
||||
const int CHANCE_CLEAR_TO_RAINY = 6;
|
||||
const int CHANCE_CLEAR_TO_STORMY = 5;
|
||||
@@ -357,7 +358,7 @@ const int FALL_DAMAGE_MAX = 4;
|
||||
|
||||
// Base Automation
|
||||
const int RESIDENT_COLLECTION_CHANCE = 10; // 10% chance per basket per hour
|
||||
const int RESIDENT_FORAGING_CHANCE = 50; // 50% chance per resident per attempt (daily)
|
||||
const int RESIDENT_FORAGING_CHANCE = 50; // 50% chance per resident per attempt (daily)
|
||||
|
||||
// Utility functions
|
||||
int abs(int value) {
|
||||
|
||||
@@ -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)",
|
||||
"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)"
|
||||
};
|
||||
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)"};
|
||||
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);
|
||||
}
|
||||
|
||||
+140
-78
@@ -1,20 +1,18 @@
|
||||
// Crafting tools
|
||||
void run_tools_menu() {
|
||||
int selection = 0;
|
||||
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)",
|
||||
"Rope (3 Vines)",
|
||||
"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)"
|
||||
};
|
||||
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)",
|
||||
"Rope (3 Vines)",
|
||||
"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)"};
|
||||
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);
|
||||
}
|
||||
|
||||
+78
-46
@@ -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;
|
||||
@@ -49,7 +49,7 @@ class Bandit {
|
||||
|
||||
// Wandering behavior properties
|
||||
string behavior_state; // "aggressive" or "wandering"
|
||||
int wander_direction; // -1, 0, or 1
|
||||
int wander_direction; // -1, 0, or 1
|
||||
timer wander_direction_timer;
|
||||
int wander_direction_change_interval;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -15,7 +15,7 @@ class GroundGame {
|
||||
int area_start;
|
||||
int area_end;
|
||||
int wander_direction; // -1, 0, 1
|
||||
string animal_type; // "boar", future: "mountain_goat", "ram", etc.
|
||||
string animal_type; // "boar", future: "mountain_goat", "ram", etc.
|
||||
bool in_weapon_range;
|
||||
|
||||
GroundGame(int pos, int start, int end, string type = "boar") {
|
||||
@@ -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);
|
||||
@@ -175,10 +185,11 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
|
||||
|
||||
// Don't leave area or enter base
|
||||
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);
|
||||
}
|
||||
game.position = target;
|
||||
if (audio_active) {
|
||||
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE,
|
||||
BOAR_SOUND_VOLUME_STEP);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Wandering
|
||||
@@ -188,12 +199,13 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
|
||||
|
||||
if (game.wander_direction != 0) {
|
||||
int target = game.position + game.wander_direction;
|
||||
// Don't leave area or enter base
|
||||
// Don't leave area or enter base
|
||||
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
|
||||
game.position = target;
|
||||
if (audio_active) {
|
||||
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
|
||||
}
|
||||
game.position = target;
|
||||
if (audio_active) {
|
||||
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");
|
||||
}
|
||||
|
||||
+140
-112
@@ -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,34 +559,34 @@ 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();
|
||||
target.minutes_since_depletion = 0;
|
||||
|
||||
|
||||
// Stop the looping sound
|
||||
if (target.sound_handle != -1) {
|
||||
p.destroy_sound(target.sound_handle);
|
||||
target.sound_handle = -1;
|
||||
}
|
||||
|
||||
|
||||
// Play the falling sound at the tree's position
|
||||
p.play_1d("sounds/items/tree.ogg", x, target.position, false);
|
||||
|
||||
|
||||
int sticks_dropped = random(1, 3);
|
||||
int vines_dropped = random(1, 2);
|
||||
int sticks_added = add_to_stack(get_personal_count(ITEM_STICKS), sticks_dropped);
|
||||
@@ -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;
|
||||
@@ -723,15 +745,16 @@ void perform_search(int current_x)
|
||||
|
||||
// Check for snares nearby (adjacent within range)
|
||||
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.
|
||||
// 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,20 +845,18 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
if (nearest.depleted) {
|
||||
speak_with_history("This tree is empty.", true);
|
||||
return;
|
||||
speak_with_history("This tree is empty.", true);
|
||||
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;
|
||||
|
||||
@@ -880,15 +900,13 @@ 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() {
|
||||