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:
Storm Dragon
2026-02-22 20:50:24 -05:00
parent 536075563f
commit b77b895685
59 changed files with 3956 additions and 2290 deletions
+18
View File
@@ -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
...
+76
View File
@@ -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
View File
@@ -1,5 +1,17 @@
string get_footstep_sound(int current_x, int base_end, int grass_end)
{
bool audio_asset_exists(const string& in soundFile) {
if (file_exists(soundFile)) {
return true;
}
pack @activePack = cast<pack @>(sound_default_pack);
if (@activePack != null && activePack.file_exists(soundFile)) {
return true;
}
return false;
}
string get_footstep_sound(int current_x, int base_end, int grass_end) {
// Check if in water first (regular streams or mountain streams)
if (is_deep_stream_at(current_x)) {
return "sounds/terrain/deep_water.ogg";
@@ -13,25 +25,18 @@ string get_footstep_sound(int current_x, int base_end, int grass_end)
return "sounds/terrain/hard_stone.ogg";
}
if (current_x <= base_end)
{
if (current_x <= base_end) {
// Base area
return "sounds/terrain/wood.ogg";
}
else if (current_x <= grass_end)
{
} else if (current_x <= grass_end) {
// Grass area
return "sounds/terrain/grass.ogg";
}
else if (current_x <= GRAVEL_END)
{
} else if (current_x <= GRAVEL_END) {
// Gravel area
return "sounds/terrain/gravel.ogg";
}
else if (expanded_area_start != -1 && current_x >= expanded_area_start && current_x <= expanded_area_end)
{
} else if (expanded_area_start != -1 && current_x >= expanded_area_start && current_x <= expanded_area_end) {
// Check for mountain terrain first
MountainRange@ mountain = get_mountain_at(current_x);
MountainRange @mountain = get_mountain_at(current_x);
if (mountain !is null) {
string terrain = mountain.get_terrain_at(current_x);
if (terrain == "stone") {
@@ -49,8 +54,7 @@ string get_footstep_sound(int current_x, int base_end, int grass_end)
// Regular expanded area - check terrain type
int index = current_x - expanded_area_start;
if (index >= 0 && index < int(expanded_terrain_types.length()))
{
if (index >= 0 && index < int(expanded_terrain_types.length())) {
string terrain = expanded_terrain_types[index];
// Handle "mountain:terrain" format from older saves
if (terrain.find("mountain:") == 0) {
@@ -76,47 +80,39 @@ string get_footstep_sound(int current_x, int base_end, int grass_end)
return "sounds/terrain/gravel.ogg";
}
void play_footstep(int current_x, int base_end, int grass_end)
{
void play_footstep(int current_x, int base_end, int grass_end) {
string sound_file = get_footstep_sound(current_x, base_end, grass_end);
if(file_exists(sound_file)) {
if (audio_asset_exists(sound_file)) {
p.play_stationary(sound_file, false);
}
}
int to_audio_position(int tile_x)
{
int to_audio_position(int tile_x) {
return tile_x * AUDIO_TILE_SCALE;
}
float to_audio_volume_step(float volume_step)
{
float to_audio_volume_step(float volume_step) {
return volume_step / float(AUDIO_TILE_SCALE);
}
int play_1d_tile(string sound_file, int listener_x, int sound_x, bool looping, bool persistent = false)
{
int play_1d_tile(string sound_file, int listener_x, int sound_x, bool looping, bool persistent = false) {
return p.play_1d(sound_file, to_audio_position(listener_x), to_audio_position(sound_x), looping, persistent);
}
bool update_sound_1d_tile(int slot, int sound_x)
{
bool update_sound_1d_tile(int slot, int sound_x) {
return p.update_sound_1d(slot, to_audio_position(sound_x));
}
void update_listener_tile(int listener_x)
{
void update_listener_tile(int listener_x) {
p.update_listener_1d(to_audio_position(listener_x));
}
void update_sound_range_1d_tile(int slot, int range_tiles)
{
void update_sound_range_1d_tile(int slot, int range_tiles) {
p.update_sound_range_1d(slot, range_tiles * AUDIO_TILE_SCALE, range_tiles * AUDIO_TILE_SCALE);
}
int play_1d_with_volume_step(string sound_file, int listener_x, int sound_x, bool looping, float volume_step)
{
int play_1d_with_volume_step(string sound_file, int listener_x, int sound_x, bool looping, float volume_step) {
int slot = p.play_1d(sound_file, listener_x, sound_x, looping);
if (slot != -1) {
p.update_sound_positioning_values(slot, -1.0, volume_step, true);
@@ -124,31 +120,29 @@ int play_1d_with_volume_step(string sound_file, int listener_x, int sound_x, boo
return slot;
}
void play_positional_footstep(int listener_x, int step_x, int base_end, int grass_end, int max_distance, float volume_step)
{
void play_positional_footstep(int listener_x, int step_x, int base_end, int grass_end, int max_distance,
float volume_step) {
if (abs(step_x - listener_x) > max_distance) {
return;
}
string sound_file = get_footstep_sound(step_x, base_end, grass_end);
if(file_exists(sound_file)) {
if (audio_asset_exists(sound_file)) {
play_1d_with_volume_step(sound_file, listener_x, step_x, false, volume_step);
}
}
void play_land_sound(int current_x, int base_end, int grass_end)
{
void play_land_sound(int current_x, int base_end, int grass_end) {
// Reusing the same logic to play the terrain sound on landing
string sound_file = get_footstep_sound(current_x, base_end, grass_end);
if(file_exists(sound_file)) {
if (audio_asset_exists(sound_file)) {
p.play_stationary(sound_file, false);
}
}
string get_item_collect_sound(string itemName)
{
string get_item_collect_sound(string itemName) {
string lookupName = itemName;
if (lookupName == "sticks") {
lookupName = "stick";
@@ -167,16 +161,15 @@ string get_item_collect_sound(string itemName)
}
string soundFile = "sounds/items/" + lookupName + ".ogg";
if (file_exists(soundFile)) {
if (audio_asset_exists(soundFile)) {
return soundFile;
}
return "sounds/items/miscellaneous.ogg";
}
void play_item_collect_sound(string itemName)
{
void play_item_collect_sound(string itemName) {
string soundFile = get_item_collect_sound(itemName);
if (file_exists(soundFile)) {
if (audio_asset_exists(soundFile)) {
p.play_stationary(soundFile, false);
}
}
@@ -190,14 +183,13 @@ string get_player_damage_sound() {
void play_player_damage_sound() {
string soundFile = get_player_damage_sound();
if (file_exists(soundFile)) {
if (audio_asset_exists(soundFile)) {
p.play_stationary(soundFile, false);
}
}
// Safe sound handle cleanup - checks if handle is valid and sound is active before destroying
void safe_destroy_sound(int &inout handle)
{
void safe_destroy_sound(int& inout handle) {
if (handle != -1) {
if (p.sound_is_active(handle)) {
p.destroy_sound(handle);
@@ -215,10 +207,13 @@ void init_master_volume() {
void set_game_master_volume_db(float volume_db, bool announce = true) {
float clamped = volume_db;
if (clamped > MASTER_VOLUME_MAX_DB) clamped = MASTER_VOLUME_MAX_DB;
if (clamped < MASTER_VOLUME_MIN_DB) clamped = MASTER_VOLUME_MIN_DB;
if (clamped > MASTER_VOLUME_MAX_DB)
clamped = MASTER_VOLUME_MAX_DB;
if (clamped < MASTER_VOLUME_MIN_DB)
clamped = MASTER_VOLUME_MIN_DB;
if (clamped == master_volume_db) return;
if (clamped == master_volume_db)
return;
master_volume_db = clamped;
sound_master_volume = master_volume_db;
@@ -227,8 +222,10 @@ void set_game_master_volume_db(float volume_db, bool announce = true) {
float range = MASTER_VOLUME_MAX_DB - MASTER_VOLUME_MIN_DB;
float normalized = (master_volume_db - MASTER_VOLUME_MIN_DB) / range;
int volumePercent = int(normalized * 100.0f + 0.5f);
if (volumePercent < 0) volumePercent = 0;
if (volumePercent > 100) volumePercent = 100;
if (volumePercent < 0)
volumePercent = 0;
if (volumePercent > 100)
volumePercent = 100;
screen_reader_speak("Volume " + volumePercent + ".", true);
}
}
+243 -146
View File
@@ -1,6 +1,7 @@
// Base automation helpers
int get_food_requirement() {
if (residents_count <= 0) return 0;
if (residents_count <= 0)
return 0;
return residents_count; // 1 food per resident per 8 hours
}
@@ -13,7 +14,8 @@ bool has_any_storage_food() {
}
bool has_any_streams() {
if (world_streams.length() > 0) return true;
if (world_streams.length() > 0)
return true;
for (uint i = 0; i < world_mountains.length(); i++) {
if (world_mountains[i].stream_positions.length() > 0) {
return true;
@@ -36,49 +38,64 @@ int get_resident_effect_multiplier() {
}
int get_horse_success_bonus() {
if (world_stables.length() == 0) return 0;
if (world_storages.length() == 0) return 0;
if (horses_count <= 0) return 0;
if (world_stables.length() == 0)
return 0;
if (world_storages.length() == 0)
return 0;
if (horses_count <= 0)
return 0;
int count = horses_count;
if (count > MAX_HORSES) count = MAX_HORSES;
if (count > MAX_HORSES)
count = MAX_HORSES;
return count * HORSE_SUCCESS_BONUS_PER;
}
int get_horse_resident_cooldown_reduction() {
if (world_stables.length() == 0) return 0;
if (world_storages.length() == 0) return 0;
if (horses_count <= 0) return 0;
if (world_stables.length() == 0)
return 0;
if (world_storages.length() == 0)
return 0;
if (horses_count <= 0)
return 0;
int count = horses_count;
if (count > MAX_HORSES) count = MAX_HORSES;
if (count > MAX_HORSES)
count = MAX_HORSES;
int cooldown_range = RESIDENT_COMBAT_BASE_COOLDOWN - RESIDENT_COMBAT_TARGET_COOLDOWN;
if (cooldown_range <= 0) return 0;
if (cooldown_range <= 0)
return 0;
return (cooldown_range * count) / MAX_HORSES;
}
int get_resident_success_chance(int base_chance) {
int chance = base_chance * get_resident_effect_multiplier();
chance += get_horse_success_bonus();
if (chance > 100) chance = 100;
if (chance > 100)
chance = 100;
return chance;
}
int get_resident_break_chance(int base_chance) {
if (!blessing_resident_active) return base_chance;
if (!blessing_resident_active)
return base_chance;
int reduced = base_chance / get_resident_effect_multiplier();
if (reduced < 1 && base_chance > 0) reduced = 1;
if (reduced < 1 && base_chance > 0)
reduced = 1;
return reduced;
}
int get_resident_escape_chance(int base_chance) {
if (!blessing_resident_active) return base_chance;
if (!blessing_resident_active)
return base_chance;
int reduced = base_chance / get_resident_effect_multiplier();
if (reduced < 1 && base_chance > 0) reduced = 1;
if (reduced < 1 && base_chance > 0)
reduced = 1;
return reduced;
}
int get_resident_cooldown(int base_cooldown) {
int cooldown = base_cooldown / get_resident_effect_multiplier();
if (cooldown < 1) cooldown = 1;
if (cooldown < 1)
cooldown = 1;
return cooldown;
}
@@ -100,7 +117,8 @@ int apply_resident_damage_bonus(int damage) {
void consume_food_for_residents() {
int needed = get_food_requirement();
if (needed <= 0) return;
if (needed <= 0)
return;
int meat_available = get_storage_count(ITEM_MEAT);
int smoked_fish_available = get_storage_count(ITEM_SMOKED_FISH);
int basket_food_available = get_storage_count(ITEM_BASKET_FOOD);
@@ -132,15 +150,21 @@ void consume_food_for_residents() {
}
void attempt_resident_fishing() {
if (!is_daytime) return;
if (residents_count <= 0) return;
if (get_storage_count(ITEM_FISHING_POLES) <= 0) return;
if (!has_any_streams()) return;
if (get_storage_count(ITEM_FISH) >= get_storage_stack_limit()) return;
if (!is_daytime)
return;
if (residents_count <= 0)
return;
if (get_storage_count(ITEM_FISHING_POLES) <= 0)
return;
if (!has_any_streams())
return;
if (get_storage_count(ITEM_FISH) >= get_storage_stack_limit())
return;
int active_fishers = residents_count;
int poles = get_storage_count(ITEM_FISHING_POLES);
if (poles < active_fishers) active_fishers = poles;
if (poles < active_fishers)
active_fishers = poles;
int caught = 0;
int poles_broken = 0;
@@ -152,8 +176,10 @@ void attempt_resident_fishing() {
poles_broken++;
continue;
}
if (random(1, 100) > fishing_chance) continue;
if (get_storage_count(ITEM_FISH) >= get_storage_stack_limit()) break;
if (random(1, 100) > fishing_chance)
continue;
if (get_storage_count(ITEM_FISH) >= get_storage_stack_limit())
break;
add_storage_count(ITEM_FISH, 1);
add_storage_fish_weight(random(FISH_WEIGHT_MIN, FISH_WEIGHT_MAX));
caught++;
@@ -163,9 +189,8 @@ void attempt_resident_fishing() {
if (poles_broken > 0) {
add_storage_count(ITEM_FISHING_POLES, -poles_broken);
if (x <= BASE_END) {
string msg = (poles_broken == 1)
? "A resident's fishing pole broke."
: poles_broken + " fishing poles broke.";
string msg =
(poles_broken == 1) ? "A resident's fishing pole broke." : poles_broken + " fishing poles broke.";
speak_with_history(msg, true);
}
}
@@ -180,22 +205,31 @@ void attempt_resident_fishing() {
}
void attempt_resident_fish_smoking() {
if (!is_daytime) return;
if (residents_count <= 0) return;
if (get_storage_count(ITEM_FISH) <= 0) return;
if (get_storage_count(ITEM_STICKS) <= 0) return;
if (!has_burning_fire_in_base()) return;
if (!is_daytime)
return;
if (residents_count <= 0)
return;
if (get_storage_count(ITEM_FISH) <= 0)
return;
if (get_storage_count(ITEM_STICKS) <= 0)
return;
if (!has_burning_fire_in_base())
return;
int attempts = get_resident_effect_multiplier();
int smoke_chance = get_resident_success_chance(RESIDENT_SMOKE_FISH_CHANCE);
for (int attempt = 0; attempt < attempts; attempt++) {
if (get_storage_count(ITEM_FISH) <= 0) return;
if (get_storage_count(ITEM_STICKS) <= 0) return;
if (random(1, 100) > smoke_chance) continue;
if (get_storage_count(ITEM_FISH) <= 0)
return;
if (get_storage_count(ITEM_STICKS) <= 0)
return;
if (random(1, 100) > smoke_chance)
continue;
int weight = (storage_fish_weights.length() > 0) ? storage_fish_weights[0] : get_default_fish_weight();
int yield = get_smoked_fish_yield(weight);
if (get_storage_count(ITEM_SMOKED_FISH) + yield > get_storage_stack_limit()) return;
if (get_storage_count(ITEM_SMOKED_FISH) + yield > get_storage_stack_limit())
return;
pop_storage_fish_weight();
add_storage_count(ITEM_FISH, -1);
@@ -209,12 +243,16 @@ void attempt_resident_fish_smoking() {
}
void attempt_livestock_production() {
if (world_pastures.length() == 0) return;
if (world_storages.length() == 0) return;
if (livestock_count <= 0) return;
if (world_pastures.length() == 0)
return;
if (world_storages.length() == 0)
return;
if (livestock_count <= 0)
return;
int count = livestock_count;
if (count > MAX_LIVESTOCK) count = MAX_LIVESTOCK;
if (count > MAX_LIVESTOCK)
count = MAX_LIVESTOCK;
int meat_produced = 0;
int skins_produced = 0;
@@ -246,9 +284,12 @@ void attempt_livestock_production() {
if ((meat_produced > 0 || skins_produced > 0 || feathers_produced > 0) && x <= BASE_END) {
string msg = "Livestock produced ";
string[] outputs;
if (meat_produced > 0) outputs.insert_last(meat_produced + " meat");
if (skins_produced > 0) outputs.insert_last(skins_produced + " skins");
if (feathers_produced > 0) outputs.insert_last(feathers_produced + " feathers");
if (meat_produced > 0)
outputs.insert_last(meat_produced + " meat");
if (skins_produced > 0)
outputs.insert_last(skins_produced + " skins");
if (feathers_produced > 0)
outputs.insert_last(feathers_produced + " feathers");
for (uint i = 0; i < outputs.length(); i++) {
if (i > 0) {
@@ -266,8 +307,10 @@ void attempt_livestock_production() {
}
void keep_base_fires_fed() {
if (residents_count <= 0) return;
if (get_storage_count(ITEM_VINES) <= 0 && get_storage_count(ITEM_STICKS) <= 0 && get_storage_count(ITEM_LOGS) <= 0) return;
if (residents_count <= 0)
return;
if (get_storage_count(ITEM_VINES) <= 0 && get_storage_count(ITEM_STICKS) <= 0 && get_storage_count(ITEM_LOGS) <= 0)
return;
// Residents tend fires once per in-game hour from time_system.
// Keep a 1-hour buffer above the 24-hour floor so fuel does not dip below 24 between hourly checks.
@@ -278,9 +321,12 @@ void keep_base_fires_fed() {
const int log_fuel_ms = 720000; // 12 hours
for (uint i = 0; i < world_fires.length(); i++) {
if (world_fires[i].position > BASE_END) continue;
if (!world_fires[i].is_burning()) continue;
if (world_fires[i].fuel_remaining >= fire_target_ms) continue;
if (world_fires[i].position > BASE_END)
continue;
if (!world_fires[i].is_burning())
continue;
if (world_fires[i].fuel_remaining >= fire_target_ms)
continue;
while (world_fires[i].fuel_remaining < fire_target_ms) {
int needed = fire_target_ms - world_fires[i].fuel_remaining;
@@ -333,13 +379,15 @@ bool remove_random_stored_runed_weapon(int equipType) {
for (uint i = 0; i < runeTypes.length(); i++) {
total += get_stored_runed_item_count(equipType, runeTypes[i]);
}
if (total <= 0) return false;
if (total <= 0)
return false;
int roll = random(1, total);
int running = 0;
for (uint i = 0; i < runeTypes.length(); i++) {
int count = get_stored_runed_item_count(equipType, runeTypes[i]);
if (count <= 0) continue;
if (count <= 0)
continue;
running += count;
if (roll <= running) {
remove_stored_runed_item(equipType, runeTypes[i]);
@@ -353,11 +401,13 @@ bool remove_random_stored_weapon(int equipType, int itemType) {
int unrunedCount = get_storage_count(itemType);
int runedCount = get_stored_runed_weapon_count(equipType);
int total = unrunedCount + runedCount;
if (total <= 0) return false;
if (total <= 0)
return false;
int roll = random(1, total);
if (roll <= unrunedCount) {
if (unrunedCount > 0) add_storage_count(itemType, -1);
if (unrunedCount > 0)
add_storage_count(itemType, -1);
return true;
}
return remove_random_stored_runed_weapon(equipType);
@@ -379,26 +429,27 @@ int get_available_defense_weapons() {
}
bool can_residents_defend() {
if (residents_count <= 0) return false;
if (residents_count <= 0)
return false;
return get_available_defense_weapons() > 0;
}
int choose_defense_weapon_type() {
// Prefer bows if available
int bowCount = (get_storage_count(ITEM_ARROWS) > 0)
? get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS)
: 0;
if (bowCount > 0) return RESIDENT_WEAPON_BOW;
int bowCount = (get_storage_count(ITEM_ARROWS) > 0) ? get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS) : 0;
if (bowCount > 0)
return RESIDENT_WEAPON_BOW;
int spearCount = get_total_stored_weapon_count(EQUIP_SPEAR, ITEM_SPEARS);
int slingCount = (get_storage_count(ITEM_STONES) > 0)
? get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS)
: 0;
int slingCount = (get_storage_count(ITEM_STONES) > 0) ? get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS) : 0;
int total = spearCount + slingCount;
if (total == 0) return RESIDENT_WEAPON_SPEAR;
if (slingCount == 0) return RESIDENT_WEAPON_SPEAR;
if (spearCount == 0) return RESIDENT_WEAPON_SLING;
if (total == 0)
return RESIDENT_WEAPON_SPEAR;
if (slingCount == 0)
return RESIDENT_WEAPON_SPEAR;
if (spearCount == 0)
return RESIDENT_WEAPON_SLING;
int roll = random(1, total);
return (roll <= spearCount) ? RESIDENT_WEAPON_SPEAR : RESIDENT_WEAPON_SLING;
@@ -407,18 +458,16 @@ int choose_defense_weapon_type() {
timer resident_combat_timer;
int perform_resident_defense(int target_pos) {
if (!can_residents_defend()) return 0;
if (resident_combat_timer.elapsed < get_resident_combat_cooldown()) return 0;
if (!can_residents_defend())
return 0;
if (resident_combat_timer.elapsed < get_resident_combat_cooldown())
return 0;
// Choose weapon type (bows preferred, otherwise weighted by availability)
int weapon_type = choose_defense_weapon_type();
int bowCount = (get_storage_count(ITEM_ARROWS) > 0)
? get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS)
: 0;
int bowCount = (get_storage_count(ITEM_ARROWS) > 0) ? get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS) : 0;
int spearCount = get_total_stored_weapon_count(EQUIP_SPEAR, ITEM_SPEARS);
int slingCount = (get_storage_count(ITEM_STONES) > 0)
? get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS)
: 0;
int slingCount = (get_storage_count(ITEM_STONES) > 0) ? get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS) : 0;
int damage = 0;
if (weapon_type == RESIDENT_WEAPON_BOW && bowCount > 0) {
@@ -432,7 +481,8 @@ int perform_resident_defense(int target_pos) {
damage = apply_resident_damage_bonus(RESIDENT_SPEAR_DAMAGE);
// Weapons don't get consumed on use - they break via daily breakage check
// Just play the sound
play_1d_with_volume_step("sounds/weapons/spear_swing.ogg", x, BASE_END + 1, false, RESIDENT_DEFENSE_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/spear_swing.ogg", x, BASE_END + 1, false,
RESIDENT_DEFENSE_VOLUME_STEP);
} else if (weapon_type == RESIDENT_WEAPON_SLING && slingCount > 0) {
damage = apply_resident_damage_bonus(random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX));
// Slings use stones as ammo, so consume a stone
@@ -450,15 +500,18 @@ int perform_resident_defense(int target_pos) {
// Proactive resident ranged defense
void attempt_resident_ranged_defense() {
// Only if residents exist and have ranged weapons
if (residents_count <= 0) return;
if (residents_count <= 0)
return;
int bowCount = get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS);
int slingCount = get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS);
bool has_bow = (bowCount > 0 && get_storage_count(ITEM_ARROWS) > 0);
bool has_sling = (slingCount > 0 && get_storage_count(ITEM_STONES) > 0);
if (!has_bow && !has_sling) return;
if (!has_bow && !has_sling)
return;
// Shared cooldown for all resident combat actions
if (resident_combat_timer.elapsed < get_resident_combat_cooldown()) return;
if (resident_combat_timer.elapsed < get_resident_combat_cooldown())
return;
int range = has_bow ? BOW_RANGE : SLING_RANGE;
// Find nearest enemy within range
@@ -489,7 +542,8 @@ void attempt_resident_ranged_defense() {
}
// No targets in range
if (targetPos == -1) return;
if (targetPos == -1)
return;
// Shoot!
resident_combat_timer.restart();
@@ -523,13 +577,15 @@ void attempt_resident_ranged_defense() {
}
void process_daily_weapon_breakage() {
if (residents_count <= 0) return;
if (residents_count <= 0)
return;
int spearTotal = get_total_stored_weapon_count(EQUIP_SPEAR, ITEM_SPEARS);
int slingTotal = get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS);
int bowTotal = get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS);
int totalWeapons = spearTotal + slingTotal + bowTotal;
if (totalWeapons == 0) return;
if (totalWeapons == 0)
return;
// Number of breakage checks = min(residents, weapons)
int checksToPerform = (residents_count < totalWeapons) ? residents_count : totalWeapons;
@@ -545,7 +601,8 @@ void process_daily_weapon_breakage() {
int remainingBows = bowTotal - bowChecks;
int remaining = remainingSpears + remainingSlings + remainingBows;
if (remaining <= 0) break;
if (remaining <= 0)
break;
int roll = random(1, remaining);
if (roll <= remainingSpears && remainingSpears > 0) {
@@ -586,9 +643,8 @@ void process_daily_weapon_breakage() {
for (int i = 0; i < spearsBroken; i++) {
remove_random_stored_weapon(EQUIP_SPEAR, ITEM_SPEARS);
}
string msg = (spearsBroken == 1)
? "A resident's spear broke from wear."
: spearsBroken + " spears broke from wear.";
string msg =
(spearsBroken == 1) ? "A resident's spear broke from wear." : spearsBroken + " spears broke from wear.";
notify(msg);
}
@@ -596,9 +652,8 @@ void process_daily_weapon_breakage() {
for (int i = 0; i < slingsBroken; i++) {
remove_random_stored_weapon(EQUIP_SLING, ITEM_SLINGS);
}
string msg = (slingsBroken == 1)
? "A resident's sling broke from wear."
: slingsBroken + " slings broke from wear.";
string msg =
(slingsBroken == 1) ? "A resident's sling broke from wear." : slingsBroken + " slings broke from wear.";
notify(msg);
}
@@ -606,15 +661,14 @@ void process_daily_weapon_breakage() {
for (int i = 0; i < bowsBroken; i++) {
remove_random_stored_weapon(EQUIP_BOW, ITEM_BOWS);
}
string msg = (bowsBroken == 1)
? "A resident's bow broke from wear."
: bowsBroken + " bows broke from wear.";
string msg = (bowsBroken == 1) ? "A resident's bow broke from wear." : bowsBroken + " bows broke from wear.";
notify(msg);
}
}
void attempt_resident_clothing_repairs() {
if (residents_count <= 0) return;
if (residents_count <= 0)
return;
int threshold = get_storage_stack_limit() / 2;
if (threshold < RESIDENT_CLOTHING_REPAIR_COST) {
@@ -648,7 +702,8 @@ void attempt_resident_clothing_repairs() {
best_count = down_count;
}
if (best_item == -1) break;
if (best_item == -1)
break;
add_storage_count(best_item, -RESIDENT_CLOTHING_REPAIR_COST);
repairs_done++;
@@ -663,13 +718,14 @@ void attempt_resident_clothing_repairs() {
}
if (repairs_done > 0 && x <= BASE_END) {
string msg = (repairs_done == 1)
? "A resident is mending clothing."
: "Residents are mending clothing.";
string msg = (repairs_done == 1) ? "A resident is mending clothing." : "Residents are mending clothing.";
string[] materials;
if (vines_used > 0) materials.insert_last(vines_used + " vines");
if (skins_used > 0) materials.insert_last(skins_used + " skins");
if (down_used > 0) materials.insert_last(down_used + " down");
if (vines_used > 0)
materials.insert_last(vines_used + " vines");
if (skins_used > 0)
materials.insert_last(skins_used + " skins");
if (down_used > 0)
materials.insert_last(down_used + " down");
if (materials.length() > 0) {
msg += " Used ";
@@ -693,35 +749,43 @@ void attempt_resident_clothing_repairs() {
// Resident snare retrieval
void attempt_resident_snare_retrieval() {
// Only during daytime
if (!is_daytime) return;
if (!is_daytime)
return;
// Need residents
if (residents_count <= 0) return;
if (residents_count <= 0)
return;
// Need food in storage (same limitation as other resident tasks)
if (!has_any_storage_food()) return;
if (!has_any_storage_food())
return;
int check_chance = get_resident_success_chance(RESIDENT_SNARE_CHECK_CHANCE);
int escape_chance = get_resident_escape_chance(RESIDENT_SNARE_ESCAPE_CHANCE);
// Check each snare that has a catch
for (int i = int(world_snares.length()) - 1; i >= 0; i--) {
WorldSnare@ snare = world_snares[i];
if (!snare.has_catch) continue;
if (!snare.active) continue;
WorldSnare @snare = world_snares[i];
if (!snare.has_catch)
continue;
if (!snare.active)
continue;
// Each snare has a chance to be checked by a resident this hour
if (random(1, 100) > check_chance) continue;
if (random(1, 100) > check_chance)
continue;
// Small chance the game escapes during retrieval (like normal)
if (random(1, 100) <= escape_chance) {
notify("A " + snare.catch_type + " escaped while a resident checked the snare at x " + snare.position + ".");
notify("A " + snare.catch_type + " escaped while a resident checked the snare at x " + snare.position +
".");
remove_snare_at(snare.position);
continue;
}
// Check if storage has room for small game
if (get_storage_count(ITEM_SMALL_GAME) >= get_storage_stack_limit()) continue;
if (get_storage_count(ITEM_SMALL_GAME) >= get_storage_stack_limit())
continue;
// Retrieve the game
string game_type = snare.catch_type;
@@ -746,26 +810,33 @@ void attempt_resident_snare_retrieval() {
// Resident butchering - processes up to residents_count games per day (doubled when blessed)
void attempt_resident_butchering() {
// Need residents
if (residents_count <= 0) return;
if (residents_count <= 0)
return;
// Need food in storage (same limitation as other resident tasks)
if (!has_any_storage_food()) return;
if (!has_any_storage_food())
return;
// Need game in storage
if (get_storage_count(ITEM_SMALL_GAME) <= 0 && get_storage_count(ITEM_BOAR_CARCASSES) <= 0) return;
if (get_storage_count(ITEM_SMALL_GAME) <= 0 && get_storage_count(ITEM_BOAR_CARCASSES) <= 0)
return;
// Need a knife in storage
if (get_storage_count(ITEM_KNIVES) <= 0) return;
if (get_storage_count(ITEM_KNIVES) <= 0)
return;
// Need a fire in base
if (!has_burning_fire_in_base()) return;
if (!has_burning_fire_in_base())
return;
int attempts = residents_count * get_resident_effect_multiplier();
int break_chance = get_resident_break_chance(RESIDENT_TOOL_BREAK_CHANCE);
for (int attempt = 0; attempt < attempts; attempt++) {
// Need game in storage
if (get_storage_count(ITEM_SMALL_GAME) <= 0 && get_storage_count(ITEM_BOAR_CARCASSES) <= 0) return;
if (get_storage_count(ITEM_KNIVES) <= 0) return;
if (get_storage_count(ITEM_SMALL_GAME) <= 0 && get_storage_count(ITEM_BOAR_CARCASSES) <= 0)
return;
if (get_storage_count(ITEM_KNIVES) <= 0)
return;
// Determine what to butcher (prioritize boar carcasses)
string game_type = "";
@@ -804,11 +875,16 @@ void attempt_resident_butchering() {
}
// Check storage capacity for outputs
if (meat_yield > 0 && get_storage_count(ITEM_MEAT) + meat_yield > get_storage_stack_limit()) return;
if (skins_yield > 0 && get_storage_count(ITEM_SKINS) + skins_yield > get_storage_stack_limit()) return;
if (feathers_yield > 0 && get_storage_count(ITEM_FEATHERS) + feathers_yield > get_storage_stack_limit()) return;
if (down_yield > 0 && get_storage_count(ITEM_DOWN) + down_yield > get_storage_stack_limit()) return;
if (sinew_yield > 0 && get_storage_count(ITEM_SINEW) + sinew_yield > get_storage_stack_limit()) return;
if (meat_yield > 0 && get_storage_count(ITEM_MEAT) + meat_yield > get_storage_stack_limit())
return;
if (skins_yield > 0 && get_storage_count(ITEM_SKINS) + skins_yield > get_storage_stack_limit())
return;
if (feathers_yield > 0 && get_storage_count(ITEM_FEATHERS) + feathers_yield > get_storage_stack_limit())
return;
if (down_yield > 0 && get_storage_count(ITEM_DOWN) + down_yield > get_storage_stack_limit())
return;
if (sinew_yield > 0 && get_storage_count(ITEM_SINEW) + sinew_yield > get_storage_stack_limit())
return;
// Consume the game
if (is_boar) {
@@ -827,20 +903,30 @@ void attempt_resident_butchering() {
}
// Add outputs to storage
if (meat_yield > 0) add_storage_count(ITEM_MEAT, meat_yield);
if (skins_yield > 0) add_storage_count(ITEM_SKINS, skins_yield);
if (feathers_yield > 0) add_storage_count(ITEM_FEATHERS, feathers_yield);
if (down_yield > 0) add_storage_count(ITEM_DOWN, down_yield);
if (sinew_yield > 0) add_storage_count(ITEM_SINEW, sinew_yield);
if (meat_yield > 0)
add_storage_count(ITEM_MEAT, meat_yield);
if (skins_yield > 0)
add_storage_count(ITEM_SKINS, skins_yield);
if (feathers_yield > 0)
add_storage_count(ITEM_FEATHERS, feathers_yield);
if (down_yield > 0)
add_storage_count(ITEM_DOWN, down_yield);
if (sinew_yield > 0)
add_storage_count(ITEM_SINEW, sinew_yield);
// Build notification message
string result = "Resident butchered " + game_type + ". Added ";
string[] outputs;
if (meat_yield > 0) outputs.insert_last(meat_yield + " meat");
if (skins_yield > 0) outputs.insert_last(skins_yield + " skins");
if (feathers_yield > 0) outputs.insert_last(feathers_yield + " feathers");
if (down_yield > 0) outputs.insert_last(down_yield + " down");
if (sinew_yield > 0) outputs.insert_last(sinew_yield + " sinew");
if (meat_yield > 0)
outputs.insert_last(meat_yield + " meat");
if (skins_yield > 0)
outputs.insert_last(skins_yield + " skins");
if (feathers_yield > 0)
outputs.insert_last(feathers_yield + " feathers");
if (down_yield > 0)
outputs.insert_last(down_yield + " down");
if (sinew_yield > 0)
outputs.insert_last(sinew_yield + " sinew");
for (uint i = 0; i < outputs.length(); i++) {
if (i > 0) {
@@ -862,16 +948,21 @@ void attempt_resident_butchering() {
void attempt_resident_collection() {
// Only during daytime
if (!is_daytime) return;
if (!is_daytime)
return;
// Need residents
if (residents_count <= 0) return;
if (residents_count <= 0)
return;
// Need baskets in storage to enable collection
if (get_storage_count(ITEM_REED_BASKETS) <= 0) return;
if (get_storage_count(ITEM_REED_BASKETS) <= 0)
return;
// Number of residents who can collect = min(residents, baskets)
int active_collectors = (residents_count < get_storage_count(ITEM_REED_BASKETS)) ? residents_count : get_storage_count(ITEM_REED_BASKETS);
int active_collectors = (residents_count < get_storage_count(ITEM_REED_BASKETS))
? residents_count
: get_storage_count(ITEM_REED_BASKETS);
// Each active collector has a 10% chance to collect something
int baskets_broken = 0;
@@ -884,7 +975,8 @@ void attempt_resident_collection() {
continue;
}
if (random(1, 100) > collection_chance) continue;
if (random(1, 100) > collection_chance)
continue;
// Determine what to collect (weighted random)
// Sticks and vines more common, logs and stones less common
@@ -919,9 +1011,7 @@ void attempt_resident_collection() {
if (baskets_broken > 0) {
add_storage_count(ITEM_REED_BASKETS, -baskets_broken);
if (x <= BASE_END) {
string msg = (baskets_broken == 1)
? "A resident's basket broke."
: baskets_broken + " baskets broke.";
string msg = (baskets_broken == 1) ? "A resident's basket broke." : baskets_broken + " baskets broke.";
speak_with_history(msg, true);
}
}
@@ -930,19 +1020,25 @@ void attempt_resident_collection() {
// Resident foraging - produces baskets of fruits and nuts from reed baskets
void attempt_resident_foraging() {
// Only during daytime
if (!is_daytime) return;
if (!is_daytime)
return;
// Need residents
if (residents_count <= 0) return;
if (residents_count <= 0)
return;
// Need reed baskets in storage
if (get_storage_count(ITEM_REED_BASKETS) <= 0) return;
if (get_storage_count(ITEM_REED_BASKETS) <= 0)
return;
// Check if storage has room for basket food
if (get_storage_count(ITEM_BASKET_FOOD) >= get_storage_stack_limit()) return;
if (get_storage_count(ITEM_BASKET_FOOD) >= get_storage_stack_limit())
return;
// Number of residents who can forage = min(residents, baskets)
int active_foragers = (residents_count < get_storage_count(ITEM_REED_BASKETS)) ? residents_count : get_storage_count(ITEM_REED_BASKETS);
int active_foragers = (residents_count < get_storage_count(ITEM_REED_BASKETS))
? residents_count
: get_storage_count(ITEM_REED_BASKETS);
int baskets_produced = 0;
int baskets_broken = 0;
@@ -957,10 +1053,12 @@ void attempt_resident_foraging() {
}
// Check if foraging succeeds
if (random(1, 100) > forage_chance) continue;
if (random(1, 100) > forage_chance)
continue;
// Check storage capacity
if (get_storage_count(ITEM_BASKET_FOOD) >= get_storage_stack_limit()) break;
if (get_storage_count(ITEM_BASKET_FOOD) >= get_storage_stack_limit())
break;
// Consume a reed basket and produce a basket of fruits and nuts
add_storage_count(ITEM_REED_BASKETS, -1);
@@ -972,8 +1070,7 @@ void attempt_resident_foraging() {
if (baskets_broken > 0) {
add_storage_count(ITEM_REED_BASKETS, -baskets_broken);
if (x <= BASE_END) {
string msg = (baskets_broken == 1)
? "A resident's basket broke while foraging."
string msg = (baskets_broken == 1) ? "A resident's basket broke while foraging."
: baskets_broken + " baskets broke while foraging.";
speak_with_history(msg, true);
}
+22 -29
View File
@@ -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);
}
+5 -3
View File
@@ -23,7 +23,7 @@ void run_adventure_menu(int player_x) {
}
string terrain = get_terrain_at_position(player_x);
MountainRange@ mountain = get_mountain_at(player_x);
MountainRange @mountain = get_mountain_at(player_x);
// Check available adventures based on terrain
string[] options;
@@ -62,14 +62,16 @@ void run_adventure_menu(int player_x) {
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= options.length()) selection = 0;
if (selection >= options.length())
selection = 0;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = options.length() - 1;
if (selection < 0)
selection = options.length() - 1;
speak_with_history(options[selection], true);
}
+131 -69
View File
@@ -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 {
+55 -27
View File
@@ -168,7 +168,9 @@ void run_unicorn_adventure() {
// Coordinates
if (key_pressed(KEY_X)) {
string facing_dir = (unicorn.facing == 1) ? "east" : "west";
string terrain = (player_arena_x >= BRIDGE_START && player_arena_x <= BRIDGE_END && !bridge_collapsed) ? "wood" : "grass";
string terrain = (player_arena_x >= BRIDGE_START && player_arena_x <= BRIDGE_END && !bridge_collapsed)
? "wood"
: "grass";
speak_with_history("x " + player_arena_x + ", terrain " + terrain + ". Unicorn facing " + facing_dir, true);
}
@@ -236,13 +238,15 @@ void handle_player_movement() {
player_arena_x--;
arena_walk_timer.restart();
check_player_chasm_fall();
if (player_health > 0) play_footstep_sound();
if (player_health > 0)
play_footstep_sound();
} else if (key_down(KEY_RIGHT) && player_arena_x < UNICORN_ARENA_SIZE - 1) {
player_arena_facing = 1;
player_arena_x++;
arena_walk_timer.restart();
check_player_chasm_fall();
if (player_health > 0) play_footstep_sound();
if (player_health > 0)
play_footstep_sound();
}
}
@@ -283,8 +287,10 @@ void check_player_chasm_fall() {
float height_remaining = float(total_fall - feet_fallen);
float pitch_percent = 50.0 + (50.0 * (height_remaining / float(total_fall)));
if (pitch_percent < 50.0) pitch_percent = 50.0;
if (pitch_percent > 100.0) pitch_percent = 100.0;
if (pitch_percent < 50.0)
pitch_percent = 50.0;
if (pitch_percent > 100.0)
pitch_percent = 100.0;
fall_handle = p.play_stationary_extended("sounds/actions/falling.ogg", true, 0, 0, 0, pitch_percent);
}
@@ -309,7 +315,8 @@ void update_player_jump() {
void handle_player_actions() {
// Can't attack while jumping
if (player_arena_jumping) return;
if (player_arena_jumping)
return;
bool ctrl_down = (key_down(KEY_LCTRL) || key_down(KEY_RCTRL));
@@ -360,14 +367,18 @@ void handle_player_actions() {
// Non-sling weapon attacks (existing pattern)
if (!bow_equipped && !bow_drawing && !sling_equipped && !sling_charging) {
if (fishing_pole_equipped) return;
if (fishing_pole_equipped)
return;
int weapon_type = get_unicorn_melee_weapon_type();
if (weapon_type == -1) return;
if (weapon_type == -1)
return;
int attack_cooldown = 1000;
if (weapon_type == ADVENTURE_WEAPON_SPEAR) attack_cooldown = 800;
if (weapon_type == ADVENTURE_WEAPON_AXE) attack_cooldown = 1600;
if (weapon_type == ADVENTURE_WEAPON_SPEAR)
attack_cooldown = 800;
if (weapon_type == ADVENTURE_WEAPON_AXE)
attack_cooldown = 1600;
if (ctrl_down && arena_attack_timer.elapsed > attack_cooldown) {
arena_attack_timer.restart();
@@ -380,8 +391,10 @@ void handle_player_actions() {
}
int get_unicorn_melee_weapon_type() {
if (spear_equipped) return ADVENTURE_WEAPON_SPEAR;
if (axe_equipped) return ADVENTURE_WEAPON_AXE;
if (spear_equipped)
return ADVENTURE_WEAPON_SPEAR;
if (axe_equipped)
return ADVENTURE_WEAPON_AXE;
return -1;
}
@@ -438,7 +451,8 @@ int find_unicorn_ranged_target(int player_x, int direction, int range) {
for (int dist = 1; dist <= range; dist++) {
int check_x = player_x + (dist * direction);
if (check_x < 0 || check_x >= UNICORN_ARENA_SIZE) break;
if (check_x < 0 || check_x >= UNICORN_ARENA_SIZE)
break;
if (bridge_supports_health[0] > 0 && check_x == BRIDGE_START) {
return check_x;
@@ -454,7 +468,8 @@ int find_unicorn_ranged_target(int player_x, int direction, int range) {
int unicorn_ranged_attack(int player_x, int direction, int range, int weapon_type, int damage) {
int target_x = find_unicorn_ranged_target(player_x, direction, range);
if (target_x == -1) return -1;
if (target_x == -1)
return -1;
if (target_x == unicorn.x) {
apply_unicorn_damage(damage);
@@ -482,7 +497,8 @@ int unicorn_ranged_attack(int player_x, int direction, int range, int weapon_typ
}
void mark_unicorn_defeated(bool by_fall) {
if (unicorn_defeated) return;
if (unicorn_defeated)
return;
unicorn_defeated = true;
unicorn_defeated_by_fall = by_fall;
if (by_fall) {
@@ -491,8 +507,10 @@ void mark_unicorn_defeated(bool by_fall) {
}
void apply_unicorn_damage(int damage) {
if (damage <= 0) return;
if (unicorn.health <= 0) return;
if (damage <= 0)
return;
if (unicorn.health <= 0)
return;
unicorn.health -= damage;
if (unicorn.health <= 0) {
@@ -501,12 +519,15 @@ void apply_unicorn_damage(int damage) {
}
}
bool pet_find_unicorn_target(int originPos, int referencePos, int &out targetPos, string &out targetLabel, int &out targetKind) {
bool pet_find_unicorn_target(int originPos, int referencePos, int& out targetPos, string& out targetLabel,
int& out targetKind) {
targetPos = -1;
targetLabel = "";
targetKind = -1;
if (unicorn.health <= 0) return false;
if (abs(unicorn.x - originPos) > PET_RANGE) return false;
if (unicorn.health <= 0)
return false;
if (abs(unicorn.x - originPos) > PET_RANGE)
return false;
targetPos = unicorn.x;
targetLabel = "unicorn";
targetKind = 0;
@@ -514,7 +535,8 @@ bool pet_find_unicorn_target(int originPos, int referencePos, int &out targetPos
}
bool pet_damage_unicorn_target(int targetKind, int targetPos, int damage) {
if (targetKind != 0) return false;
if (targetKind != 0)
return false;
apply_unicorn_damage(damage);
return true;
}
@@ -588,7 +610,8 @@ void update_unicorn_audio() {
}
// Check if we need to switch sounds (different file or no active sound)
bool need_new_sound = (unicorn.sound_handle == -1 || !p.sound_is_active(unicorn.sound_handle) || current_unicorn_sound != sound_file);
bool need_new_sound =
(unicorn.sound_handle == -1 || !p.sound_is_active(unicorn.sound_handle) || current_unicorn_sound != sound_file);
if (need_new_sound) {
// Stop old sound if playing
@@ -596,7 +619,8 @@ void update_unicorn_audio() {
p.destroy_sound(unicorn.sound_handle);
}
// Start new positioned sound using shared helper
unicorn.sound_handle = play_1d_with_volume_step(sound_file, player_arena_x, unicorn.x, true, UNICORN_SOUND_VOLUME_STEP);
unicorn.sound_handle =
play_1d_with_volume_step(sound_file, player_arena_x, unicorn.x, true, UNICORN_SOUND_VOLUME_STEP);
current_unicorn_sound = sound_file;
} else {
// Update position of existing sound
@@ -630,10 +654,13 @@ void play_unicorn_death_sequence() {
// Pitch ranges from 100 (start) to 50 (end) like normal falling
float height_remaining = float(total_fall - feet_fallen);
float pitch_percent = 50.0 + (50.0 * (height_remaining / float(total_fall)));
if (pitch_percent < 50.0) pitch_percent = 50.0;
if (pitch_percent > 100.0) pitch_percent = 100.0;
if (pitch_percent < 50.0)
pitch_percent = 50.0;
if (pitch_percent > 100.0)
pitch_percent = 100.0;
fall_handle = p.play_extended_1d("sounds/actions/falling.ogg", player_arena_x, unicorn.x, 0, 0, true, 0, 0.0, 0.0, pitch_percent);
fall_handle = p.play_extended_1d("sounds/actions/falling.ogg", player_arena_x, unicorn.x, 0, 0, true, 0,
0.0, 0.0, pitch_percent);
if (fall_handle != -1) {
p.update_sound_positioning_values(fall_handle, -1.0, UNICORN_SOUND_VOLUME_STEP, true);
}
@@ -645,7 +672,8 @@ void play_unicorn_death_sequence() {
if (fall_handle != -1) {
p.destroy_sound(fall_handle);
}
play_1d_with_volume_step("sounds/bosses/unicorn/unicorn_falls.ogg", player_arena_x, unicorn.x, false, UNICORN_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/bosses/unicorn/unicorn_falls.ogg", player_arena_x, unicorn.x, false,
UNICORN_SOUND_VOLUME_STEP);
wait(1500); // Let the impact sound play before cleanup
}
+53 -47
View File
@@ -30,34 +30,36 @@ void speak_ammo_blocked(string message) {
speak_with_history(message, true);
}
int find_ranged_enemy(int player_x, int range, int direction, bool allow_flying, bool &out hit_bandit, bool &out hit_boar, bool &out hit_flying_creature) {
int find_ranged_enemy(int player_x, int range, int direction, bool allow_flying, bool& out hit_bandit,
bool& out hit_boar, bool& out hit_flying_creature) {
hit_bandit = false;
hit_boar = false;
hit_flying_creature = false;
for (int dist = 1; dist <= range; dist++) {
int check_x = player_x + (dist * direction);
if (check_x < 0 || check_x >= MAP_SIZE) break;
if (check_x < 0 || check_x >= MAP_SIZE)
break;
Bandit@ bandit = get_bandit_at(check_x);
Bandit @bandit = get_bandit_at(check_x);
if (bandit != null) {
hit_bandit = true;
return check_x;
}
GroundGame@ boar = get_boar_at(check_x);
GroundGame @boar = get_boar_at(check_x);
if (boar != null) {
hit_boar = true;
return check_x;
}
Undead@ undead = get_zombie_at(check_x);
Undead @undead = get_zombie_at(check_x);
if (undead != null) {
return check_x;
}
if (allow_flying) {
FlyingCreature@ creature = get_flying_creature_at(check_x);
FlyingCreature @creature = get_flying_creature_at(check_x);
if (creature != null && creature.state == "flying") {
hit_flying_creature = true;
return check_x;
@@ -152,7 +154,7 @@ void perform_sling_attack(int current_x) {
}
void hit_tree_with_spear(int target_x) {
Tree@ target = get_tree_at(target_x);
Tree @target = get_tree_at(target_x);
if (@target != null && !target.is_chopped) {
p.play_stationary("sounds/weapons/spear_hit.ogg", false);
}
@@ -184,13 +186,17 @@ void update_sling_charge() {
int get_bow_draw_damage(int elapsed_ms) {
int clamped = elapsed_ms;
if (clamped < 0) clamped = 0;
if (clamped > BOW_DRAW_TIME_MS) clamped = BOW_DRAW_TIME_MS;
if (clamped < 0)
clamped = 0;
if (clamped > BOW_DRAW_TIME_MS)
clamped = BOW_DRAW_TIME_MS;
float ratio = float(clamped) / float(BOW_DRAW_TIME_MS);
int damage = int(ratio * BOW_DAMAGE_MAX);
if (damage < BOW_DAMAGE_MIN) damage = BOW_DAMAGE_MIN;
if (damage > BOW_DAMAGE_MAX) damage = BOW_DAMAGE_MAX;
if (damage < BOW_DAMAGE_MIN)
damage = BOW_DAMAGE_MIN;
if (damage > BOW_DAMAGE_MAX)
damage = BOW_DAMAGE_MAX;
return damage;
}
@@ -213,24 +219,23 @@ void start_bow_shot_audio(int start_x, int end_x, int hit_x, int hit_type, int d
bow_shot_duration_ms = duration_ms;
bow_shot_drop_pending = false;
bow_shot_drop_pos = -1;
if (bow_shot_duration_ms < 1) bow_shot_duration_ms = 1;
if (bow_shot_duration_ms < 1)
bow_shot_duration_ms = 1;
bow_shot_sound_handle = play_1d_with_volume_step(
"sounds/weapons/arrow_flies.ogg",
x,
bow_shot_start_x,
false,
PLAYER_WEAPON_SOUND_VOLUME_STEP
);
bow_shot_sound_handle = play_1d_with_volume_step("sounds/weapons/arrow_flies.ogg", x, bow_shot_start_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
}
void update_bow_shot() {
if (!bow_shot_active) return;
if (bow_shot_duration_ms < 1) bow_shot_duration_ms = 1;
if (!bow_shot_active)
return;
if (bow_shot_duration_ms < 1)
bow_shot_duration_ms = 1;
int elapsed = bow_shot_timer.elapsed;
float progress = float(elapsed) / float(bow_shot_duration_ms);
if (progress > 1.0f) progress = 1.0f;
if (progress > 1.0f)
progress = 1.0f;
int travel = int(float(bow_shot_end_x - bow_shot_start_x) * progress);
int current_pos = bow_shot_start_x + travel;
@@ -245,13 +250,7 @@ void update_bow_shot() {
int drop_pos = bow_shot_drop_pos;
stop_bow_shot_audio();
if (hit_x >= 0) {
play_1d_with_volume_step(
"sounds/weapons/arrow_hit.ogg",
x,
hit_x,
false,
PLAYER_WEAPON_SOUND_VOLUME_STEP
);
play_1d_with_volume_step("sounds/weapons/arrow_hit.ogg", x, hit_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
if (hit_type == BOW_HIT_BANDIT) {
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", x, hit_x, BANDIT_SOUND_VOLUME_STEP);
} else if (hit_type == BOW_HIT_BOAR) {
@@ -283,14 +282,16 @@ void release_bow_attack(int player_x) {
bool hit_bandit = false;
bool hit_flying_creature = false;
bool hit_boar = false;
int target_x = find_ranged_enemy(player_x, BOW_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
int target_x =
find_ranged_enemy(player_x, BOW_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
bool hit_tree = false;
if (target_x == -1) {
for (int dist = 1; dist <= BOW_RANGE; dist++) {
int check_x = player_x + (dist * search_direction);
if (check_x < 0 || check_x >= MAP_SIZE) break;
Tree@ tree = get_tree_at(check_x);
if (check_x < 0 || check_x >= MAP_SIZE)
break;
Tree @tree = get_tree_at(check_x);
if (tree != null && !tree.is_chopped) {
target_x = check_x;
hit_tree = true;
@@ -318,16 +319,16 @@ void release_bow_attack(int player_x) {
hit_type = BOW_HIT_NONE;
}
int end_x = (target_x != -1)
? target_x
: (player_x + (search_direction * (BOW_RANGE + BOW_MISS_EXTRA_TILES)));
int end_x = (target_x != -1) ? target_x : (player_x + (search_direction * (BOW_RANGE + BOW_MISS_EXTRA_TILES)));
int duration_ms = ARROW_FLIES_DURATION_MS;
if (target_x != -1) {
int distance = abs(target_x - player_x);
if (distance < 1) distance = 1;
if (distance < 1)
distance = 1;
duration_ms = int(float(ARROW_FLIES_DURATION_MS) * (float(distance) / float(BOW_RANGE)));
if (duration_ms < 1) duration_ms = 1;
if (duration_ms < 1)
duration_ms = 1;
}
int hit_x = (target_x != -1) ? target_x : -1;
@@ -349,7 +350,6 @@ void release_sling_attack(int player_x) {
// Only hit if released during in-range window (stage 1)
if (stage != 1) {
speak_with_history("Stone missed.", true);
return;
}
@@ -359,17 +359,20 @@ void release_sling_attack(int player_x) {
bool hit_bandit = false;
bool hit_flying_creature = false;
bool hit_boar = false;
target_x = find_ranged_enemy(player_x, SLING_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
target_x =
find_ranged_enemy(player_x, SLING_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
// If no enemy found, check for trees (but don't damage them)
if (target_x == -1) {
for (int dist = 1; dist <= SLING_RANGE; dist++) {
int check_x = player_x + (dist * search_direction);
if (check_x < 0 || check_x >= MAP_SIZE) break;
Tree@ tree = get_tree_at(check_x);
if (check_x < 0 || check_x >= MAP_SIZE)
break;
Tree @tree = get_tree_at(check_x);
if (tree != null && !tree.is_chopped) {
// Stone hits tree but doesn't damage it
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, check_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, check_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
return;
}
}
@@ -377,7 +380,6 @@ void release_sling_attack(int player_x) {
// No target found
if (target_x == -1) {
speak_with_history("Stone missed.", true);
return;
}
@@ -387,19 +389,23 @@ void release_sling_attack(int player_x) {
// Damage the correct enemy type
if (hit_bandit) {
damage_bandit_at(target_x, damage);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", player_x, target_x, BANDIT_SOUND_VOLUME_STEP);
} else if (hit_boar) {
damage_boar_at(target_x, damage);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", player_x, target_x, BOAR_SOUND_VOLUME_STEP);
} else if (hit_flying_creature) {
damage_flying_creature_at(target_x, damage);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
// Falling sound handled by damage_flying_creature_at
} else {
damage_zombie_at(target_x, damage);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", player_x, target_x, ZOMBIE_SOUND_VOLUME_STEP);
}
}
+1
View File
@@ -277,6 +277,7 @@ const int PET_KNOCKOUT_COOLDOWN_HOURS = 4;
const float PET_CHARGE_SPEED_MULTIPLIER = 1.5;
const int PET_FOLLOW_COMFORT_DISTANCE = 2;
const int PET_FOLLOW_MAX_DISTANCE = 5;
const int PET_LEAVE_DESPAWN_DISTANCE = 20;
// Goose settings
const int GOOSE_HEALTH = 1;
+55 -26
View File
@@ -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);
}
+66 -34
View File
@@ -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);
+125 -66
View File
@@ -44,18 +44,16 @@ void consume_pouches(int amount) {
void run_clothing_menu() {
int selection = 0;
string[] options = {
"Skin Hat (1 Skin, 1 Vine)",
string[] options = {"Skin Hat (1 Skin, 1 Vine)",
"Skin Gloves (1 Skin, 1 Vine)",
"Skin Pants (6 Skins, 3 Vines)",
"Skin Tunic (4 Skins, 2 Vines)",
"Moccasins (2 Skins, 1 Vine)",
"Skin Pouch (2 Skins, 1 Vine)",
"Backpack (11 Skins, 5 Vines, 4 Skin Pouches)"
};
"Backpack (11 Skins, 5 Vines, 4 Skin Pouches)"};
speak_with_history("Clothing. " + options[selection], true);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -68,38 +66,54 @@ void run_clothing_menu() {
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= options.length()) selection = 0;
if (selection >= options.length())
selection = 0;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = options.length() - 1;
if (selection < 0)
selection = options.length() - 1;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
play_menu_select_sound();
if (selection == 0) craft_skin_hat();
else if (selection == 1) craft_skin_gloves();
else if (selection == 2) craft_skin_pants();
else if (selection == 3) craft_skin_tunic();
else if (selection == 4) craft_moccasins();
else if (selection == 5) craft_skin_pouch();
else if (selection == 6) craft_backpack();
if (selection == 0)
craft_skin_hat();
else if (selection == 1)
craft_skin_gloves();
else if (selection == 2)
craft_skin_pants();
else if (selection == 3)
craft_skin_tunic();
else if (selection == 4)
craft_moccasins();
else if (selection == 5)
craft_skin_pouch();
else if (selection == 6)
craft_backpack();
break;
}
if (key_pressed(KEY_TAB)) {
play_menu_select_sound();
if (selection == 0) craft_skin_hat_max();
else if (selection == 1) craft_skin_gloves_max();
else if (selection == 2) craft_skin_pants_max();
else if (selection == 3) craft_skin_tunic_max();
else if (selection == 4) craft_moccasins_max();
else if (selection == 5) craft_skin_pouch_max();
else if (selection == 6) craft_backpack_max();
if (selection == 0)
craft_skin_hat_max();
else if (selection == 1)
craft_skin_gloves_max();
else if (selection == 2)
craft_skin_pants_max();
else if (selection == 3)
craft_skin_tunic_max();
else if (selection == 4)
craft_moccasins_max();
else if (selection == 5)
craft_skin_pouch_max();
else if (selection == 6)
craft_backpack_max();
break;
}
}
@@ -107,8 +121,10 @@ void run_clothing_menu() {
void craft_skin_hat() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 1)
missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
if (missing == "") {
if (get_personal_count(ITEM_SKIN_HATS) >= get_personal_stack_limit()) {
@@ -134,15 +150,19 @@ void craft_skin_hat_max() {
int max_by_skins = get_personal_count(ITEM_SKINS);
int max_by_vines = get_personal_count(ITEM_VINES);
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_HATS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 1)
missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -158,8 +178,10 @@ void craft_skin_hat_max() {
void craft_skin_gloves() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 1)
missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
if (missing == "") {
if (get_personal_count(ITEM_SKIN_GLOVES) >= get_personal_stack_limit()) {
@@ -185,15 +207,19 @@ void craft_skin_gloves_max() {
int max_by_skins = get_personal_count(ITEM_SKINS);
int max_by_vines = get_personal_count(ITEM_VINES);
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_GLOVES);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 1)
missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -209,8 +235,10 @@ void craft_skin_gloves_max() {
void craft_skin_pants() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
if (get_personal_count(ITEM_VINES) < 3) missing += "3 vines ";
if (get_personal_count(ITEM_SKINS) < 6)
missing += "6 skins ";
if (get_personal_count(ITEM_VINES) < 3)
missing += "3 vines ";
if (missing == "") {
if (get_personal_count(ITEM_SKIN_PANTS) >= get_personal_stack_limit()) {
@@ -236,15 +264,19 @@ void craft_skin_pants_max() {
int max_by_skins = get_personal_count(ITEM_SKINS) / 6;
int max_by_vines = get_personal_count(ITEM_VINES) / 3;
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_PANTS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
if (get_personal_count(ITEM_VINES) < 3) missing += "3 vines ";
if (get_personal_count(ITEM_SKINS) < 6)
missing += "6 skins ";
if (get_personal_count(ITEM_VINES) < 3)
missing += "3 vines ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -259,8 +291,10 @@ void craft_skin_pants_max() {
void craft_skin_tunic() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 4) missing += "4 skins ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_SKINS) < 4)
missing += "4 skins ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
if (missing == "") {
if (get_personal_count(ITEM_SKIN_TUNICS) >= get_personal_stack_limit()) {
@@ -286,15 +320,19 @@ void craft_skin_tunic_max() {
int max_by_skins = get_personal_count(ITEM_SKINS) / 4;
int max_by_vines = get_personal_count(ITEM_VINES) / 2;
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_TUNICS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 4) missing += "4 skins ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_SKINS) < 4)
missing += "4 skins ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -309,8 +347,10 @@ void craft_skin_tunic_max() {
void craft_moccasins() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
if (missing == "") {
if (get_personal_count(ITEM_MOCCASINS) >= get_personal_stack_limit()) {
@@ -336,15 +376,19 @@ void craft_moccasins_max() {
int max_by_skins = get_personal_count(ITEM_SKINS) / 2;
int max_by_vines = get_personal_count(ITEM_VINES);
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_MOCCASINS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -360,8 +404,10 @@ void craft_moccasins_max() {
void craft_skin_pouch() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
if (missing == "") {
if (get_personal_count(ITEM_SKIN_POUCHES) >= get_personal_stack_limit()) {
@@ -387,15 +433,19 @@ void craft_skin_pouch_max() {
int max_by_skins = get_personal_count(ITEM_SKINS) / 2;
int max_by_vines = get_personal_count(ITEM_VINES);
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_POUCHES);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -411,9 +461,12 @@ void craft_skin_pouch_max() {
void craft_backpack() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 11) missing += "11 skins ";
if (get_personal_count(ITEM_VINES) < 5) missing += "5 vines ";
if (get_total_pouch_count() < 4) missing += "4 skin pouches ";
if (get_personal_count(ITEM_SKINS) < 11)
missing += "11 skins ";
if (get_personal_count(ITEM_VINES) < 5)
missing += "5 vines ";
if (get_total_pouch_count() < 4)
missing += "4 skin pouches ";
if (missing == "") {
if (get_personal_count(ITEM_BACKPACKS) >= get_personal_stack_limit()) {
@@ -441,17 +494,23 @@ void craft_backpack_max() {
int max_by_vines = get_personal_count(ITEM_VINES) / 5;
int max_by_pouches = get_total_pouch_count() / 4;
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_pouches < max_craft) max_craft = max_by_pouches;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
if (max_by_pouches < max_craft)
max_craft = max_by_pouches;
int space = get_personal_stack_limit() - get_personal_count(ITEM_BACKPACKS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 11) missing += "11 skins ";
if (get_personal_count(ITEM_VINES) < 5) missing += "5 vines ";
if (get_total_pouch_count() < 4) missing += "4 skin pouches ";
if (get_personal_count(ITEM_SKINS) < 11)
missing += "11 skins ";
if (get_personal_count(ITEM_VINES) < 5)
missing += "5 vines ";
if (get_total_pouch_count() < 4)
missing += "4 skin pouches ";
speak_with_history("Missing: " + missing, true);
return;
}
+108 -62
View File
@@ -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
View File
@@ -4,68 +4,140 @@
// Get the base equipment name without any rune prefix
string get_base_equipment_name(int equip_type) {
if (equip_type == EQUIP_SPEAR) return "Spear";
if (equip_type == EQUIP_AXE) return "Stone Axe";
if (equip_type == EQUIP_SLING) return "Sling";
if (equip_type == EQUIP_BOW) return "Bow";
if (equip_type == EQUIP_HAT) return "Skin Hat";
if (equip_type == EQUIP_GLOVES) return "Skin Gloves";
if (equip_type == EQUIP_PANTS) return "Skin Pants";
if (equip_type == EQUIP_TUNIC) return "Skin Tunic";
if (equip_type == EQUIP_MOCCASINS) return "Moccasins";
if (equip_type == EQUIP_POUCH) return "Skin Pouch";
if (equip_type == EQUIP_BACKPACK) return "Backpack";
if (equip_type == EQUIP_FISHING_POLE) return "Fishing Pole";
if (equip_type == EQUIP_SPEAR)
return "Spear";
if (equip_type == EQUIP_AXE)
return "Stone Axe";
if (equip_type == EQUIP_SLING)
return "Sling";
if (equip_type == EQUIP_BOW)
return "Bow";
if (equip_type == EQUIP_HAT)
return "Skin Hat";
if (equip_type == EQUIP_GLOVES)
return "Skin Gloves";
if (equip_type == EQUIP_PANTS)
return "Skin Pants";
if (equip_type == EQUIP_TUNIC)
return "Skin Tunic";
if (equip_type == EQUIP_MOCCASINS)
return "Moccasins";
if (equip_type == EQUIP_POUCH)
return "Skin Pouch";
if (equip_type == EQUIP_BACKPACK)
return "Backpack";
if (equip_type == EQUIP_FISHING_POLE)
return "Fishing Pole";
return "Unknown";
}
string get_base_equipment_name_plural(int equip_type) {
if (equip_type == EQUIP_SPEAR) return "Spears";
if (equip_type == EQUIP_AXE) return "Stone Axes";
if (equip_type == EQUIP_SLING) return "Slings";
if (equip_type == EQUIP_BOW) return "Bows";
if (equip_type == EQUIP_HAT) return "Skin Hats";
if (equip_type == EQUIP_GLOVES) return "Skin Gloves";
if (equip_type == EQUIP_PANTS) return "Skin Pants";
if (equip_type == EQUIP_TUNIC) return "Skin Tunics";
if (equip_type == EQUIP_MOCCASINS) return "Moccasins";
if (equip_type == EQUIP_POUCH) return "Skin Pouches";
if (equip_type == EQUIP_BACKPACK) return "Backpacks";
if (equip_type == EQUIP_FISHING_POLE) return "Fishing Poles";
if (equip_type == EQUIP_SPEAR)
return "Spears";
if (equip_type == EQUIP_AXE)
return "Stone Axes";
if (equip_type == EQUIP_SLING)
return "Slings";
if (equip_type == EQUIP_BOW)
return "Bows";
if (equip_type == EQUIP_HAT)
return "Skin Hats";
if (equip_type == EQUIP_GLOVES)
return "Skin Gloves";
if (equip_type == EQUIP_PANTS)
return "Skin Pants";
if (equip_type == EQUIP_TUNIC)
return "Skin Tunics";
if (equip_type == EQUIP_MOCCASINS)
return "Moccasins";
if (equip_type == EQUIP_POUCH)
return "Skin Pouches";
if (equip_type == EQUIP_BACKPACK)
return "Backpacks";
if (equip_type == EQUIP_FISHING_POLE)
return "Fishing Poles";
return "Items";
}
// Get inventory count for an equipment type
int get_unruned_equipment_count(int equip_type) {
if (equip_type == EQUIP_SPEAR) return get_personal_count(ITEM_SPEARS);
if (equip_type == EQUIP_AXE) return get_personal_count(ITEM_AXES);
if (equip_type == EQUIP_SLING) return get_personal_count(ITEM_SLINGS);
if (equip_type == EQUIP_BOW) return get_personal_count(ITEM_BOWS);
if (equip_type == EQUIP_HAT) return get_personal_count(ITEM_SKIN_HATS);
if (equip_type == EQUIP_GLOVES) return get_personal_count(ITEM_SKIN_GLOVES);
if (equip_type == EQUIP_PANTS) return get_personal_count(ITEM_SKIN_PANTS);
if (equip_type == EQUIP_TUNIC) return get_personal_count(ITEM_SKIN_TUNICS);
if (equip_type == EQUIP_MOCCASINS) return get_personal_count(ITEM_MOCCASINS);
if (equip_type == EQUIP_POUCH) return get_personal_count(ITEM_SKIN_POUCHES);
if (equip_type == EQUIP_BACKPACK) return get_personal_count(ITEM_BACKPACKS);
if (equip_type == EQUIP_FISHING_POLE) return get_personal_count(ITEM_FISHING_POLES);
if (equip_type == EQUIP_SPEAR)
return get_personal_count(ITEM_SPEARS);
if (equip_type == EQUIP_AXE)
return get_personal_count(ITEM_AXES);
if (equip_type == EQUIP_SLING)
return get_personal_count(ITEM_SLINGS);
if (equip_type == EQUIP_BOW)
return get_personal_count(ITEM_BOWS);
if (equip_type == EQUIP_HAT)
return get_personal_count(ITEM_SKIN_HATS);
if (equip_type == EQUIP_GLOVES)
return get_personal_count(ITEM_SKIN_GLOVES);
if (equip_type == EQUIP_PANTS)
return get_personal_count(ITEM_SKIN_PANTS);
if (equip_type == EQUIP_TUNIC)
return get_personal_count(ITEM_SKIN_TUNICS);
if (equip_type == EQUIP_MOCCASINS)
return get_personal_count(ITEM_MOCCASINS);
if (equip_type == EQUIP_POUCH)
return get_personal_count(ITEM_SKIN_POUCHES);
if (equip_type == EQUIP_BACKPACK)
return get_personal_count(ITEM_BACKPACKS);
if (equip_type == EQUIP_FISHING_POLE)
return get_personal_count(ITEM_FISHING_POLES);
return 0;
}
// Decrement inventory for an equipment type
void decrement_unruned_equipment(int equip_type) {
if (equip_type == EQUIP_SPEAR) { add_personal_count(ITEM_SPEARS, -1); return; }
if (equip_type == EQUIP_AXE) { add_personal_count(ITEM_AXES, -1); return; }
if (equip_type == EQUIP_SLING) { add_personal_count(ITEM_SLINGS, -1); return; }
if (equip_type == EQUIP_BOW) { add_personal_count(ITEM_BOWS, -1); return; }
if (equip_type == EQUIP_HAT) { add_personal_count(ITEM_SKIN_HATS, -1); return; }
if (equip_type == EQUIP_GLOVES) { add_personal_count(ITEM_SKIN_GLOVES, -1); return; }
if (equip_type == EQUIP_PANTS) { add_personal_count(ITEM_SKIN_PANTS, -1); return; }
if (equip_type == EQUIP_TUNIC) { add_personal_count(ITEM_SKIN_TUNICS, -1); return; }
if (equip_type == EQUIP_MOCCASINS) { add_personal_count(ITEM_MOCCASINS, -1); return; }
if (equip_type == EQUIP_POUCH) { add_personal_count(ITEM_SKIN_POUCHES, -1); return; }
if (equip_type == EQUIP_BACKPACK) { add_personal_count(ITEM_BACKPACKS, -1); return; }
if (equip_type == EQUIP_FISHING_POLE) { add_personal_count(ITEM_FISHING_POLES, -1); return; }
if (equip_type == EQUIP_SPEAR) {
add_personal_count(ITEM_SPEARS, -1);
return;
}
if (equip_type == EQUIP_AXE) {
add_personal_count(ITEM_AXES, -1);
return;
}
if (equip_type == EQUIP_SLING) {
add_personal_count(ITEM_SLINGS, -1);
return;
}
if (equip_type == EQUIP_BOW) {
add_personal_count(ITEM_BOWS, -1);
return;
}
if (equip_type == EQUIP_HAT) {
add_personal_count(ITEM_SKIN_HATS, -1);
return;
}
if (equip_type == EQUIP_GLOVES) {
add_personal_count(ITEM_SKIN_GLOVES, -1);
return;
}
if (equip_type == EQUIP_PANTS) {
add_personal_count(ITEM_SKIN_PANTS, -1);
return;
}
if (equip_type == EQUIP_TUNIC) {
add_personal_count(ITEM_SKIN_TUNICS, -1);
return;
}
if (equip_type == EQUIP_MOCCASINS) {
add_personal_count(ITEM_MOCCASINS, -1);
return;
}
if (equip_type == EQUIP_POUCH) {
add_personal_count(ITEM_SKIN_POUCHES, -1);
return;
}
if (equip_type == EQUIP_BACKPACK) {
add_personal_count(ITEM_BACKPACKS, -1);
return;
}
if (equip_type == EQUIP_FISHING_POLE) {
add_personal_count(ITEM_FISHING_POLES, -1);
return;
}
}
void run_runes_menu() {
@@ -95,7 +167,7 @@ void run_runes_menu() {
int selection = 0;
speak_with_history("Runes. " + rune_options[selection], true);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -108,14 +180,16 @@ void run_runes_menu() {
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= int(rune_options.length())) selection = 0;
if (selection >= int(rune_options.length()))
selection = 0;
speak_with_history(rune_options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = int(rune_options.length()) - 1;
if (selection < 0)
selection = int(rune_options.length()) - 1;
speak_with_history(rune_options[selection], true);
}
@@ -150,9 +224,10 @@ void run_rune_equipment_menu(int rune_type) {
}
int selection = 0;
speak_with_history("Select equipment to engrave with " + get_rune_name(rune_type) + ". " + equipment_options[selection], true);
speak_with_history(
"Select equipment to engrave with " + get_rune_name(rune_type) + ". " + equipment_options[selection], true);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -165,14 +240,16 @@ void run_rune_equipment_menu(int rune_type) {
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= int(equipment_options.length())) selection = 0;
if (selection >= int(equipment_options.length()))
selection = 0;
speak_with_history(equipment_options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = int(equipment_options.length()) - 1;
if (selection < 0)
selection = int(equipment_options.length()) - 1;
speak_with_history(equipment_options[selection], true);
}
@@ -195,9 +272,12 @@ void run_rune_equipment_menu(int rune_type) {
void engrave_rune(int equip_type, int rune_type) {
// Validate requirements
string missing = "";
if (get_personal_count(ITEM_KNIVES) < 1) missing += "Stone Knife ";
if (get_personal_count(ITEM_CLAY) < 1) missing += "1 clay ";
if (favor < 1.0) missing += "1 favor ";
if (get_personal_count(ITEM_KNIVES) < 1)
missing += "Stone Knife ";
if (get_personal_count(ITEM_CLAY) < 1)
missing += "1 clay ";
if (favor < 1.0)
missing += "1 favor ";
// Check equipment is still available
if (get_unruned_equipment_count(equip_type) < 1) {
@@ -229,7 +309,8 @@ void engrave_rune(int equip_type, int rune_type) {
void engrave_rune_max(int equip_type, int rune_type) {
// Validate requirements
string missing = "";
if (get_personal_count(ITEM_KNIVES) < 1) missing += "Stone Knife ";
if (get_personal_count(ITEM_KNIVES) < 1)
missing += "Stone Knife ";
int unruned_count = get_unruned_equipment_count(equip_type);
if (unruned_count < 1) {
@@ -240,8 +321,10 @@ void engrave_rune_max(int equip_type, int rune_type) {
int clay_count = get_personal_count(ITEM_CLAY);
int favor_count = int(favor);
int max_craft = unruned_count;
if (clay_count < max_craft) max_craft = clay_count;
if (favor_count < max_craft) max_craft = favor_count;
if (clay_count < max_craft)
max_craft = clay_count;
if (favor_count < max_craft)
max_craft = favor_count;
if (missing != "") {
speak_with_history("Missing: " + missing, true);
@@ -249,9 +332,12 @@ void engrave_rune_max(int equip_type, int rune_type) {
}
if (max_craft <= 0) {
if (clay_count < 1) missing += "1 clay ";
if (favor < 1.0) missing += "1 favor ";
if (missing == "") missing = "resources";
if (clay_count < 1)
missing += "1 clay ";
if (favor < 1.0)
missing += "1 favor ";
if (missing == "")
missing = "resources";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -267,6 +353,7 @@ void engrave_rune_max(int equip_type, int rune_type) {
simulate_crafting(6 * max_craft);
string item_name = (max_craft == 1) ? get_base_equipment_name(equip_type) : get_base_equipment_name_plural(equip_type);
string item_name =
(max_craft == 1) ? get_base_equipment_name(equip_type) : get_base_equipment_name_plural(equip_type);
speak_with_history("Engraved " + max_craft + " " + item_name + " with " + get_rune_name(rune_type) + ".", true);
}
+133 -71
View File
@@ -1,8 +1,7 @@
// Crafting tools
void run_tools_menu() {
int selection = 0;
string[] options = {
"Stone Knife (2 Stones)",
string[] options = {"Stone Knife (2 Stones)",
"Snare (1 Stick, 2 Vines)",
"Stone Axe (1 Stick, 1 Vine, 2 Stones) [Requires Knife]",
"Fishing Pole (1 Stick, 2 Vines)",
@@ -10,11 +9,10 @@ void run_tools_menu() {
"Quiver (2 Skins, 2 Vines)",
"Canoe (4 Logs, 11 Sticks, 11 Vines, 6 Skins, 2 Rope, 6 Reeds)",
"Reed Basket (3 Reeds)",
"Clay Pot (3 Clay)"
};
"Clay Pot (3 Clay)"};
speak_with_history("Tools. " + options[selection], true);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -27,42 +25,62 @@ void run_tools_menu() {
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= options.length()) selection = 0;
if (selection >= options.length())
selection = 0;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = options.length() - 1;
if (selection < 0)
selection = options.length() - 1;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
play_menu_select_sound();
if (selection == 0) craft_knife();
else if (selection == 1) craft_snare();
else if (selection == 2) craft_axe();
else if (selection == 3) craft_fishing_pole();
else if (selection == 4) craft_rope();
else if (selection == 5) craft_quiver();
else if (selection == 6) craft_canoe();
else if (selection == 7) craft_reed_basket();
else if (selection == 8) craft_clay_pot();
if (selection == 0)
craft_knife();
else if (selection == 1)
craft_snare();
else if (selection == 2)
craft_axe();
else if (selection == 3)
craft_fishing_pole();
else if (selection == 4)
craft_rope();
else if (selection == 5)
craft_quiver();
else if (selection == 6)
craft_canoe();
else if (selection == 7)
craft_reed_basket();
else if (selection == 8)
craft_clay_pot();
break;
}
if (key_pressed(KEY_TAB)) {
play_menu_select_sound();
if (selection == 0) craft_knife_max();
else if (selection == 1) craft_snare_max();
else if (selection == 2) craft_axe_max();
else if (selection == 3) craft_fishing_pole_max();
else if (selection == 4) craft_rope_max();
else if (selection == 5) craft_quiver_max();
else if (selection == 6) craft_canoe_max();
else if (selection == 7) craft_reed_basket_max();
else if (selection == 8) craft_clay_pot_max();
if (selection == 0)
craft_knife_max();
else if (selection == 1)
craft_snare_max();
else if (selection == 2)
craft_axe_max();
else if (selection == 3)
craft_fishing_pole_max();
else if (selection == 4)
craft_rope_max();
else if (selection == 5)
craft_quiver_max();
else if (selection == 6)
craft_canoe_max();
else if (selection == 7)
craft_reed_basket_max();
else if (selection == 8)
craft_clay_pot_max();
break;
}
}
@@ -70,7 +88,8 @@ void run_tools_menu() {
void craft_knife() {
string missing = "";
if (get_personal_count(ITEM_STONES) < 2) missing += "2 stones ";
if (get_personal_count(ITEM_STONES) < 2)
missing += "2 stones ";
if (missing == "") {
if (get_personal_count(ITEM_KNIVES) >= get_personal_stack_limit()) {
@@ -94,7 +113,8 @@ void craft_knife_max() {
int max_possible = get_personal_count(ITEM_STONES) / 2;
int space = get_personal_stack_limit() - get_personal_count(ITEM_KNIVES);
if (max_possible > space) max_possible = space;
if (max_possible > space)
max_possible = space;
if (max_possible <= 0) {
speak_with_history("Missing: 2 stones", true);
@@ -111,8 +131,10 @@ void craft_knife_max() {
void craft_snare() {
string missing = "";
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_STICKS) < 1)
missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
if (missing == "") {
if (get_personal_count(ITEM_SNARES) >= get_personal_stack_limit()) {
@@ -138,15 +160,19 @@ void craft_snare_max() {
int max_by_sticks = get_personal_count(ITEM_STICKS);
int max_by_vines = get_personal_count(ITEM_VINES) / 2;
int max_craft = max_by_sticks;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SNARES);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_STICKS) < 1)
missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -162,8 +188,10 @@ void craft_snare_max() {
void craft_fishing_pole() {
string missing = "";
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_STICKS) < 1)
missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
if (missing == "") {
if (get_personal_count(ITEM_FISHING_POLES) >= get_personal_stack_limit()) {
@@ -189,15 +217,19 @@ void craft_fishing_pole_max() {
int max_by_sticks = get_personal_count(ITEM_STICKS);
int max_by_vines = get_personal_count(ITEM_VINES) / 2;
int max_craft = max_by_sticks;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_FISHING_POLES);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_STICKS) < 1)
missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -213,7 +245,8 @@ void craft_fishing_pole_max() {
void craft_rope() {
string missing = "";
if (get_personal_count(ITEM_VINES) < 3) missing += "3 vines ";
if (get_personal_count(ITEM_VINES) < 3)
missing += "3 vines ";
if (missing == "") {
if (get_personal_count(ITEM_ROPES) >= get_personal_stack_limit()) {
@@ -238,7 +271,8 @@ void craft_rope_max() {
int max_craft = get_personal_count(ITEM_VINES) / 3;
int space = get_personal_stack_limit() - get_personal_count(ITEM_ROPES);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
speak_with_history("Missing: 3 vines", true);
@@ -255,8 +289,10 @@ void craft_rope_max() {
void craft_quiver() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
if (missing == "") {
if (get_personal_count(ITEM_QUIVERS) >= get_personal_stack_limit()) {
@@ -282,15 +318,19 @@ void craft_quiver_max() {
int maxBySkins = get_personal_count(ITEM_SKINS) / 2;
int maxByVines = get_personal_count(ITEM_VINES) / 2;
int maxCraft = maxBySkins;
if (maxByVines < maxCraft) maxCraft = maxByVines;
if (maxByVines < maxCraft)
maxCraft = maxByVines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_QUIVERS);
if (maxCraft > space) maxCraft = space;
if (maxCraft > space)
maxCraft = space;
if (maxCraft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -306,12 +346,18 @@ void craft_quiver_max() {
void craft_canoe() {
string missing = "";
if (get_personal_count(ITEM_LOGS) < 4) missing += "4 logs ";
if (get_personal_count(ITEM_STICKS) < 11) missing += "11 sticks ";
if (get_personal_count(ITEM_VINES) < 11) missing += "11 vines ";
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
if (get_personal_count(ITEM_ROPES) < 2) missing += "2 rope ";
if (get_personal_count(ITEM_REEDS) < 6) missing += "6 reeds ";
if (get_personal_count(ITEM_LOGS) < 4)
missing += "4 logs ";
if (get_personal_count(ITEM_STICKS) < 11)
missing += "11 sticks ";
if (get_personal_count(ITEM_VINES) < 11)
missing += "11 vines ";
if (get_personal_count(ITEM_SKINS) < 6)
missing += "6 skins ";
if (get_personal_count(ITEM_ROPES) < 2)
missing += "2 rope ";
if (get_personal_count(ITEM_REEDS) < 6)
missing += "6 reeds ";
if (missing == "") {
if (get_personal_count(ITEM_CANOES) >= get_personal_stack_limit()) {
@@ -345,23 +391,35 @@ void craft_canoe_max() {
int maxByRopes = get_personal_count(ITEM_ROPES) / 2;
int maxByReeds = get_personal_count(ITEM_REEDS) / 6;
int maxCraft = maxByLogs;
if (maxBySticks < maxCraft) maxCraft = maxBySticks;
if (maxByVines < maxCraft) maxCraft = maxByVines;
if (maxBySkins < maxCraft) maxCraft = maxBySkins;
if (maxByRopes < maxCraft) maxCraft = maxByRopes;
if (maxByReeds < maxCraft) maxCraft = maxByReeds;
if (maxBySticks < maxCraft)
maxCraft = maxBySticks;
if (maxByVines < maxCraft)
maxCraft = maxByVines;
if (maxBySkins < maxCraft)
maxCraft = maxBySkins;
if (maxByRopes < maxCraft)
maxCraft = maxByRopes;
if (maxByReeds < maxCraft)
maxCraft = maxByReeds;
int space = get_personal_stack_limit() - get_personal_count(ITEM_CANOES);
if (maxCraft > space) maxCraft = space;
if (maxCraft > space)
maxCraft = space;
if (maxCraft <= 0) {
string missing = "";
if (get_personal_count(ITEM_LOGS) < 4) missing += "4 logs ";
if (get_personal_count(ITEM_STICKS) < 11) missing += "11 sticks ";
if (get_personal_count(ITEM_VINES) < 11) missing += "11 vines ";
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
if (get_personal_count(ITEM_ROPES) < 2) missing += "2 rope ";
if (get_personal_count(ITEM_REEDS) < 6) missing += "6 reeds ";
if (get_personal_count(ITEM_LOGS) < 4)
missing += "4 logs ";
if (get_personal_count(ITEM_STICKS) < 11)
missing += "11 sticks ";
if (get_personal_count(ITEM_VINES) < 11)
missing += "11 vines ";
if (get_personal_count(ITEM_SKINS) < 6)
missing += "6 skins ";
if (get_personal_count(ITEM_ROPES) < 2)
missing += "2 rope ";
if (get_personal_count(ITEM_REEDS) < 6)
missing += "6 reeds ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -381,7 +439,8 @@ void craft_canoe_max() {
void craft_reed_basket() {
string missing = "";
if (get_personal_count(ITEM_REEDS) < 3) missing += "3 reeds ";
if (get_personal_count(ITEM_REEDS) < 3)
missing += "3 reeds ";
if (missing == "") {
if (get_personal_count(ITEM_REED_BASKETS) >= get_personal_stack_limit()) {
@@ -406,7 +465,8 @@ void craft_reed_basket_max() {
int max_craft = get_personal_count(ITEM_REEDS) / 3;
int space = get_personal_stack_limit() - get_personal_count(ITEM_REED_BASKETS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
speak_with_history("Missing: 3 reeds", true);
@@ -423,10 +483,11 @@ void craft_reed_basket_max() {
void craft_clay_pot() {
string missing = "";
if (get_personal_count(ITEM_CLAY) < 3) missing += "3 clay ";
if (get_personal_count(ITEM_CLAY) < 3)
missing += "3 clay ";
// Check for fire within 3 tiles (can hear it)
WorldFire@ fire = get_fire_within_range(x, 3);
WorldFire @fire = get_fire_within_range(x, 3);
if (fire == null) {
speak_with_history("You need a fire within 3 tiles to craft a clay pot.", true);
return;
@@ -448,7 +509,7 @@ void craft_clay_pot() {
void craft_clay_pot_max() {
// Check for fire within 3 tiles (can hear it)
WorldFire@ fire = get_fire_within_range(x, 3);
WorldFire @fire = get_fire_within_range(x, 3);
if (fire == null) {
speak_with_history("You need a fire within 3 tiles to craft clay pots.", true);
return;
@@ -462,7 +523,8 @@ void craft_clay_pot_max() {
int max_craft = get_personal_count(ITEM_CLAY) / 3;
int space = get_personal_stack_limit() - get_personal_count(ITEM_CLAY_POTS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
speak_with_history("Missing: 3 clay", true);
+83 -46
View File
@@ -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;
}
+22 -13
View File
@@ -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
View File
@@ -46,15 +46,16 @@ const int CREATURE_DEFAULT_FOOTSTEP_DISTANCE = 6;
// Plays a creature's voice/alert sound with consistent positioning
// Returns the sound handle for tracking
int play_creature_voice(string sound_file, int listener_x, int creature_x, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
{
int play_creature_voice(string sound_file, int listener_x, int creature_x,
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
return play_1d_with_volume_step(sound_file, listener_x, creature_x, false, volume_step);
}
// Plays a creature's footstep sound with consistent positioning
// Only plays if within max_distance to avoid cluttering the soundscape
void play_creature_footstep(int listener_x, int creature_x, int base_end, int grass_end, int max_distance = CREATURE_DEFAULT_FOOTSTEP_DISTANCE, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
{
void play_creature_footstep(int listener_x, int creature_x, int base_end, int grass_end,
int max_distance = CREATURE_DEFAULT_FOOTSTEP_DISTANCE,
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
int distance = creature_x - listener_x;
if (distance < 0) {
distance = -distance;
@@ -68,19 +69,18 @@ void play_creature_footstep(int listener_x, int creature_x, int base_end, int gr
}
// Plays a creature attack sound (hitting player, hitting barricade, etc.)
void play_creature_attack_sound(string sound_file, int listener_x, int creature_x, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
{
void play_creature_attack_sound(string sound_file, int listener_x, int creature_x,
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
play_1d_with_volume_step(sound_file, listener_x, creature_x, false, volume_step);
}
// Plays a creature death/fall sound
void play_creature_death_sound(string sound_file, int listener_x, int creature_x, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
{
void play_creature_death_sound(string sound_file, int listener_x, int creature_x,
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
play_1d_with_volume_step(sound_file, listener_x, creature_x, false, volume_step);
}
string get_creature_death_sound_from_alert(string alert_sound)
{
string get_creature_death_sound_from_alert(string alert_sound) {
if (alert_sound == "") {
return "";
}
@@ -98,7 +98,7 @@ string get_creature_death_sound_from_alert(string alert_sound)
if (filename == "bandit3" || filename == "bandit4") {
string female_death = "sounds/enemies/bandit_female_dies.ogg";
if (file_exists(female_death)) {
if (audio_asset_exists(female_death)) {
return female_death;
}
}
@@ -118,15 +118,15 @@ string get_creature_death_sound_from_alert(string alert_sound)
}
string death_sound = "sounds/enemies/" + filename + "_dies.ogg";
if (!file_exists(death_sound)) {
if (!audio_asset_exists(death_sound)) {
return "";
}
return death_sound;
}
void play_creature_death_sounds(string default_sound, string alert_sound, int listener_x, int creature_x, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
{
void play_creature_death_sounds(string default_sound, string alert_sound, int listener_x, int creature_x,
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
play_creature_death_sound(default_sound, listener_x, creature_x, volume_step);
string death_sound = get_creature_death_sound_from_alert(alert_sound);
@@ -136,7 +136,7 @@ void play_creature_death_sounds(string default_sound, string alert_sound, int li
}
// Plays a creature hit/damage sound (when player damages the creature)
void play_creature_hit_sound(string sound_file, int listener_x, int creature_x, float volume_step = CREATURE_DEFAULT_VOLUME_STEP)
{
void play_creature_hit_sound(string sound_file, int listener_x, int creature_x,
float volume_step = CREATURE_DEFAULT_VOLUME_STEP) {
play_1d_with_volume_step(sound_file, listener_x, creature_x, false, volume_step);
}
+77 -45
View File
@@ -3,7 +3,7 @@
string[] bandit_sounds = {"sounds/enemies/bandit1.ogg", "sounds/enemies/bandit2.ogg"};
string[] get_invader_sound_list(const string&in invader_type) {
string[] get_invader_sound_list(const string& in invader_type) {
string[] sounds;
if (invader_type == "") {
return sounds;
@@ -11,7 +11,7 @@ string[] get_invader_sound_list(const string&in invader_type) {
for (int i = 1; i <= INVADER_SOUND_VARIANTS_MAX; i++) {
string sound_file = "sounds/enemies/" + invader_type + i + ".ogg";
if (file_exists(sound_file)) {
if (audio_asset_exists(sound_file)) {
sounds.insert_last(sound_file);
}
}
@@ -19,7 +19,7 @@ string[] get_invader_sound_list(const string&in invader_type) {
return sounds;
}
string pick_invader_alert_sound(const string&in invader_type) {
string pick_invader_alert_sound(const string& in invader_type) {
string[] sounds = get_invader_sound_list(invader_type);
if (sounds.length() == 0) {
sounds = bandit_sounds;
@@ -89,12 +89,12 @@ class Bandit {
// Initialize wandering behavior (start aggressive during invasion)
behavior_state = "aggressive";
wander_direction = 0;
wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
wander_direction_change_interval =
random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
wander_direction_timer.restart();
in_weapon_range = false;
}
}
Bandit@[] bandits;
} Bandit @[] bandits;
void update_bandit_weapon_range_audio() {
for (uint i = 0; i < bandits.length(); i++) {
@@ -104,12 +104,14 @@ void update_bandit_weapon_range_audio() {
bool bandit_range_audio_registered = false;
void ensure_bandit_range_audio_registration() {
if (bandit_range_audio_registered) return;
if (bandit_range_audio_registered)
return;
bandit_range_audio_registered = register_weapon_range_audio_callback(@update_bandit_weapon_range_audio);
}
void clear_bandits() {
if (bandits.length() == 0) return;
if (bandits.length() == 0)
return;
for (uint i = 0; i < bandits.length(); i++) {
force_weapon_range_exit(bandits[i].position, bandits[i].in_weapon_range);
@@ -121,7 +123,7 @@ void clear_bandits() {
bandits.resize(0);
}
Bandit@ get_bandit_at(int pos) {
Bandit @get_bandit_at(int pos) {
for (uint i = 0; i < bandits.length(); i++) {
if (bandits[i].position == pos) {
return @bandits[i];
@@ -141,14 +143,18 @@ int pick_bandit_spawn_position(int range_start, int range_end) {
for (int attempts = 0; attempts < 20; attempts++) {
int candidate = random(start, end);
if (candidate == x) continue;
if (get_bandit_at(candidate) != null) continue;
if (candidate == x)
continue;
if (get_bandit_at(candidate) != null)
continue;
return candidate;
}
for (int candidate = start; candidate <= end; candidate++) {
if (candidate == x) continue;
if (get_bandit_at(candidate) != null) continue;
if (candidate == x)
continue;
if (get_bandit_at(candidate) != null)
continue;
return candidate;
}
@@ -158,7 +164,8 @@ int pick_bandit_spawn_position(int range_start, int range_end) {
int pick_bandit_spawn_east_of_player(int min_distance, int max_distance, int range_start, int range_end) {
int min_dist = min_distance;
int max_dist = max_distance;
if (min_dist < 0) min_dist = 0;
if (min_dist < 0)
min_dist = 0;
if (max_dist < min_dist) {
int temp = min_dist;
min_dist = max_dist;
@@ -176,10 +183,13 @@ int pick_bandit_spawn_east_of_player(int min_distance, int max_distance, int ran
range_end_norm = temp;
}
if (start < range_start_norm) start = range_start_norm;
if (end > range_end_norm) end = range_end_norm;
if (start < range_start_norm)
start = range_start_norm;
if (end > range_end_norm)
end = range_end_norm;
if (start > end) return -1;
if (start > end)
return -1;
return pick_bandit_spawn_position(start, end);
}
@@ -187,7 +197,8 @@ int pick_bandit_spawn_east_of_player(int min_distance, int max_distance, int ran
int pick_bandit_spawn_west_of_player(int min_distance, int max_distance, int range_start, int range_end) {
int min_dist = min_distance;
int max_dist = max_distance;
if (min_dist < 0) min_dist = 0;
if (min_dist < 0)
min_dist = 0;
if (max_dist < min_dist) {
int temp = min_dist;
min_dist = max_dist;
@@ -205,29 +216,38 @@ int pick_bandit_spawn_west_of_player(int min_distance, int max_distance, int ran
range_end_norm = temp;
}
if (start < range_start_norm) start = range_start_norm;
if (end > range_end_norm) end = range_end_norm;
if (start < range_start_norm)
start = range_start_norm;
if (end > range_end_norm)
end = range_end_norm;
if (start > end) return -1;
if (start > end)
return -1;
return pick_bandit_spawn_position(start, end);
}
int pick_bandit_spawn_near_player(int range_start, int range_end) {
// Preferred: 30-50 tiles east of player.
int spawn_x = pick_bandit_spawn_east_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1) return spawn_x;
int spawn_x =
pick_bandit_spawn_east_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1)
return spawn_x;
// Fallback: 30-50 tiles west when east side is not available.
spawn_x = pick_bandit_spawn_west_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1) return spawn_x;
spawn_x =
pick_bandit_spawn_west_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1)
return spawn_x;
// If map bounds are tight, relax minimum distance but keep around player.
spawn_x = pick_bandit_spawn_east_of_player(1, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1) return spawn_x;
if (spawn_x != -1)
return spawn_x;
spawn_x = pick_bandit_spawn_west_of_player(1, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1) return spawn_x;
if (spawn_x != -1)
return spawn_x;
return -1;
}
@@ -250,7 +270,7 @@ int count_bandits_in_range(int range_start, int range_end) {
return count;
}
void spawn_bandit(int expansion_start, int expansion_end, const string&in invader_type = "bandit") {
void spawn_bandit(int expansion_start, int expansion_end, const string& in invader_type = "bandit") {
int spawn_x = -1;
if (invasion_active) {
spawn_x = pick_bandit_spawn_near_player(expansion_start, expansion_end);
@@ -258,7 +278,8 @@ void spawn_bandit(int expansion_start, int expansion_end, const string&in invade
if (spawn_x == -1) {
spawn_x = pick_bandit_spawn_position(expansion_start, expansion_end);
}
if (spawn_x == -1) return;
if (spawn_x == -1)
return;
int home_start = expansion_start;
int home_end = expansion_end;
@@ -271,7 +292,7 @@ void spawn_bandit(int expansion_start, int expansion_end, const string&in invade
}
}
Bandit@ b = Bandit(spawn_x, home_start, home_end, invader_type);
Bandit @b = Bandit(spawn_x, home_start, home_end, invader_type);
if (!invasion_active) {
b.behavior_state = "wandering";
}
@@ -285,7 +306,7 @@ void spawn_bandit(int expansion_start, int expansion_end, const string&in invade
}
}
bool can_bandit_attack_player(Bandit@ bandit) {
bool can_bandit_attack_player(Bandit @bandit) {
if (player_health <= 0) {
return false;
}
@@ -302,7 +323,7 @@ bool can_bandit_attack_player(Bandit@ bandit) {
return y <= BANDIT_ATTACK_MAX_HEIGHT;
}
bool try_attack_player_bandit(Bandit@ bandit) {
bool try_attack_player_bandit(Bandit @bandit) {
if (!can_bandit_attack_player(bandit)) {
return false;
}
@@ -336,16 +357,19 @@ bool try_attack_player_bandit(Bandit@ bandit) {
return true;
}
void try_attack_barricade_bandit(Bandit@ bandit) {
if (barricade_health <= 0) return;
if (bandit.attack_timer.elapsed < BANDIT_ATTACK_INTERVAL) return;
void try_attack_barricade_bandit(Bandit @bandit) {
if (barricade_health <= 0)
return;
if (bandit.attack_timer.elapsed < BANDIT_ATTACK_INTERVAL)
return;
bandit.attack_timer.restart();
// Bandits do 1-2 damage to barricade
int damage = random(BANDIT_DAMAGE_MIN, BANDIT_DAMAGE_MAX);
barricade_health -= damage;
if (barricade_health < 0) barricade_health = 0;
if (barricade_health < 0)
barricade_health = 0;
// Play weapon swing sound (barricade hits share a common impact sound)
if (bandit.weapon_type == "spear") {
@@ -372,7 +396,7 @@ void try_attack_barricade_bandit(Bandit@ bandit) {
}
}
void update_bandit(Bandit@ bandit, bool audio_active) {
void update_bandit(Bandit @bandit, bool audio_active) {
bool enforce_home = (!invasion_active && bandit.home_start <= bandit.home_end);
if (enforce_home) {
if (bandit.position < bandit.home_start) {
@@ -395,14 +419,16 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
if (bandit.sound_handle != -1) {
p.destroy_sound(bandit.sound_handle);
}
bandit.sound_handle = play_1d_with_volume_step(bandit.alert_sound, x, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
bandit.sound_handle =
play_1d_with_volume_step(bandit.alert_sound, x, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
}
if (try_attack_player_bandit(bandit)) {
return;
}
if (bandit.move_timer.elapsed < bandit.move_interval) return;
if (bandit.move_timer.elapsed < bandit.move_interval)
return;
bandit.move_timer.restart();
// If barricade is up and bandit is at the edge of base, attack barricade
@@ -423,7 +449,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
if (bandit.wander_direction_timer.elapsed > bandit.wander_direction_change_interval) {
// Time to change direction
bandit.wander_direction = random(-1, 1);
bandit.wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
bandit.wander_direction_change_interval =
random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
bandit.wander_direction_timer.restart();
}
@@ -444,7 +471,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
} else {
bandit.position = target_x;
if (audio_active) {
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END,
BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
}
}
} else {
@@ -479,7 +507,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
}
int target_x = bandit.position + direction;
if (target_x < 0 || target_x >= MAP_SIZE) return;
if (target_x < 0 || target_x >= MAP_SIZE)
return;
if (enforce_home && (target_x < bandit.home_start || target_x > bandit.home_end)) {
return;
@@ -493,7 +522,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
bandit.position = target_x;
if (audio_active) {
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE,
BANDIT_SOUND_VOLUME_STEP);
}
}
}
@@ -506,7 +536,8 @@ void update_bandits() {
bool limit_audio = (areaStarts.length() > 0);
for (uint i = 0; i < bandits.length(); i++) {
bool audio_active = !limit_audio || range_overlaps_active_areas(bandits[i].position, bandits[i].position, areaStarts, areaEnds);
bool audio_active =
!limit_audio || range_overlaps_active_areas(bandits[i].position, bandits[i].position, areaStarts, areaEnds);
update_bandit(bandits[i], audio_active);
}
}
@@ -520,7 +551,8 @@ bool damage_bandit_at(int pos, int damage) {
p.destroy_sound(bandits[i].sound_handle);
bandits[i].sound_handle = -1;
}
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", bandits[i].alert_sound, x, pos, BANDIT_SOUND_VOLUME_STEP);
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", bandits[i].alert_sound, x, pos,
BANDIT_SOUND_VOLUME_STEP);
bandits.remove_at(i);
}
return true;
+73 -47
View File
@@ -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;
+57 -30
View File
@@ -36,8 +36,7 @@ class GroundGame {
next_move_delay = random(BOAR_MOVE_INTERVAL_MIN, BOAR_MOVE_INTERVAL_MAX);
in_weapon_range = false;
}
}
GroundGame@[] ground_games;
} GroundGame @[] ground_games;
void update_ground_game_weapon_range_audio() {
for (uint i = 0; i < ground_games.length(); i++) {
@@ -47,12 +46,14 @@ void update_ground_game_weapon_range_audio() {
bool ground_game_range_audio_registered = false;
void ensure_ground_game_range_audio_registration() {
if (ground_game_range_audio_registered) return;
if (ground_game_range_audio_registered)
return;
ground_game_range_audio_registered = register_weapon_range_audio_callback(@update_ground_game_weapon_range_audio);
}
void clear_ground_games() {
if (ground_games.length() == 0) return;
if (ground_games.length() == 0)
return;
for (uint i = 0; i < ground_games.length(); i++) {
force_weapon_range_exit(ground_games[i].position, ground_games[i].in_weapon_range);
@@ -64,7 +65,7 @@ void clear_ground_games() {
ground_games.resize(0);
}
GroundGame@ get_ground_game_at(int pos) {
GroundGame @get_ground_game_at(int pos) {
for (uint i = 0; i < ground_games.length(); i++) {
if (ground_games[i].position == pos) {
return @ground_games[i];
@@ -80,16 +81,18 @@ void spawn_ground_game(int expansion_start, int expansion_end) {
int candidate = random(expansion_start, expansion_end);
// Don't spawn too close to base (keep away from BASE_END)
if (candidate <= BASE_END + 5) continue;
if (candidate <= BASE_END + 5)
continue;
if (get_ground_game_at(candidate) == null) {
spawn_x = candidate;
break;
}
}
if (spawn_x == -1) return; // Failed to find spot
if (spawn_x == -1)
return; // Failed to find spot
GroundGame@ b = GroundGame(spawn_x, expansion_start, expansion_end, "boar");
GroundGame @b = GroundGame(spawn_x, expansion_start, expansion_end, "boar");
ground_games.insert_last(b);
// Play looping sound that follows the boar
int[] areaStarts;
@@ -100,34 +103,40 @@ void spawn_ground_game(int expansion_start, int expansion_end) {
}
}
bool can_ground_game_attack_player(GroundGame@ game) {
if (player_health <= 0) return false;
bool can_ground_game_attack_player(GroundGame @game) {
if (player_health <= 0)
return false;
// Check if player is on ground (ground game can't fly/climb)
if (y > 0) return false;
if (y > 0)
return false;
if (abs(game.position - x) > 1) return false;
if (abs(game.position - x) > 1)
return false;
return true;
}
bool try_attack_player_ground_game(GroundGame@ game) {
if (!can_ground_game_attack_player(game)) return false;
bool try_attack_player_ground_game(GroundGame @game) {
if (!can_ground_game_attack_player(game))
return false;
if (game.attack_timer.elapsed < BOAR_ATTACK_INTERVAL) return false;
if (game.attack_timer.elapsed < BOAR_ATTACK_INTERVAL)
return false;
game.attack_timer.restart();
// Attack!
int damage = random(BOAR_DAMAGE_MIN, BOAR_DAMAGE_MAX);
player_health -= damage;
if (player_health < 0) player_health = 0;
if (player_health < 0)
player_health = 0;
play_player_damage_sound();
return true;
}
void update_ground_game(GroundGame@ game, bool audio_active) {
void update_ground_game(GroundGame @game, bool audio_active) {
// Update looping sound position
if (!audio_active) {
if (game.sound_handle != -1) {
@@ -152,7 +161,8 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
// Movement logic
int move_speed = (game.state == "charging") ? BOAR_CHARGE_SPEED : game.next_move_delay;
if (game.move_timer.elapsed < move_speed) return;
if (game.move_timer.elapsed < move_speed)
return;
game.move_timer.restart();
if (game.state == "wandering") {
game.next_move_delay = random(BOAR_MOVE_INTERVAL_MIN, BOAR_MOVE_INTERVAL_MAX);
@@ -177,7 +187,8 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
game.position = target;
if (audio_active) {
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE,
BOAR_SOUND_VOLUME_STEP);
}
}
} else {
@@ -192,7 +203,8 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
game.position = target;
if (audio_active) {
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE,
BOAR_SOUND_VOLUME_STEP);
}
} else {
game.wander_direction = -game.wander_direction; // Turn around
@@ -209,14 +221,17 @@ void update_ground_games() {
bool limit_audio = (areaStarts.length() > 0);
for (uint i = 0; i < ground_games.length(); i++) {
bool audio_active = !limit_audio || range_overlaps_active_areas(ground_games[i].position, ground_games[i].position, areaStarts, areaEnds);
bool audio_active = !limit_audio || range_overlaps_active_areas(ground_games[i].position,
ground_games[i].position, areaStarts, areaEnds);
update_ground_game(ground_games[i], audio_active);
}
}
void attempt_hourly_ground_game_spawn() {
if (expanded_area_start == -1) return;
if (ground_games.length() >= BOAR_MAX_COUNT) return;
if (expanded_area_start == -1)
return;
if (ground_games.length() >= BOAR_MAX_COUNT)
return;
if (random(1, 100) <= BOAR_SPAWN_CHANCE_PER_HOUR) {
spawn_ground_game(expanded_area_start, expanded_area_end);
@@ -246,10 +261,22 @@ bool damage_ground_game_at(int pos, int damage) {
}
// Backward compatibility aliases (to be removed after refactoring)
GroundGame@[]@ boars = @ground_games;
GroundGame@ get_boar_at(int pos) { return get_ground_game_at(pos); }
void clear_boars() { clear_ground_games(); }
void spawn_boar(int expansion_start, int expansion_end) { spawn_ground_game(expansion_start, expansion_end); }
void update_boars() { update_ground_games(); }
void attempt_hourly_boar_spawn() { attempt_hourly_ground_game_spawn(); }
bool damage_boar_at(int pos, int damage) { return damage_ground_game_at(pos, damage); }
GroundGame @[] @boars = @ground_games;
GroundGame @get_boar_at(int pos) {
return get_ground_game_at(pos);
}
void clear_boars() {
clear_ground_games();
}
void spawn_boar(int expansion_start, int expansion_end) {
spawn_ground_game(expansion_start, expansion_end);
}
void update_boars() {
update_ground_games();
}
void attempt_hourly_boar_spawn() {
attempt_hourly_ground_game_spawn();
}
bool damage_boar_at(int pos, int damage) {
return damage_ground_game_at(pos, damage);
}
+131 -77
View File
@@ -3,12 +3,8 @@
string[] undead_zombie_sounds = {"sounds/enemies/zombie1.ogg"};
string[] undead_wight_sounds = {"sounds/enemies/wight1.ogg"};
string[] undead_vampyr_sounds = {
"sounds/enemies/vampyr1.ogg",
"sounds/enemies/vampyr2.ogg",
"sounds/enemies/vampyr3.ogg",
"sounds/enemies/vampyr4.ogg"
};
string[] undead_vampyr_sounds = {"sounds/enemies/vampyr1.ogg", "sounds/enemies/vampyr2.ogg",
"sounds/enemies/vampyr3.ogg", "sounds/enemies/vampyr4.ogg"};
string[] undead_resident_sounds = {"sounds/enemies/undead_resident1.ogg"};
int wight_spawn_chance = WIGHT_SPAWN_CHANCE_START;
@@ -16,28 +12,37 @@ int wight_spawned_this_night_count = 0;
int vampyr_spawn_chance = VAMPYR_SPAWN_CHANCE_START;
int vampyr_spawned_this_night_count = 0;
int get_undead_base_health(const string &in undead_type) {
if (undead_type == "wight") return WIGHT_HEALTH;
if (undead_type == "vampyr") return VAMPYR_HEALTH;
if (undead_type == "undead_resident") return UNDEAD_RESIDENT_HEALTH;
int get_undead_base_health(const string& in undead_type) {
if (undead_type == "wight")
return WIGHT_HEALTH;
if (undead_type == "vampyr")
return VAMPYR_HEALTH;
if (undead_type == "undead_resident")
return UNDEAD_RESIDENT_HEALTH;
return ZOMBIE_HEALTH;
}
int get_undead_damage_min(const string &in undead_type) {
if (undead_type == "wight") return WIGHT_DAMAGE_MIN;
if (undead_type == "vampyr") return WIGHT_DAMAGE_MIN;
if (undead_type == "undead_resident") return UNDEAD_RESIDENT_DAMAGE_MIN;
int get_undead_damage_min(const string& in undead_type) {
if (undead_type == "wight")
return WIGHT_DAMAGE_MIN;
if (undead_type == "vampyr")
return WIGHT_DAMAGE_MIN;
if (undead_type == "undead_resident")
return UNDEAD_RESIDENT_DAMAGE_MIN;
return ZOMBIE_DAMAGE_MIN;
}
int get_undead_damage_max(const string &in undead_type) {
if (undead_type == "wight") return WIGHT_DAMAGE_MAX;
if (undead_type == "vampyr") return WIGHT_DAMAGE_MAX;
if (undead_type == "undead_resident") return UNDEAD_RESIDENT_DAMAGE_MAX;
int get_undead_damage_max(const string& in undead_type) {
if (undead_type == "wight")
return WIGHT_DAMAGE_MAX;
if (undead_type == "vampyr")
return WIGHT_DAMAGE_MAX;
if (undead_type == "undead_resident")
return UNDEAD_RESIDENT_DAMAGE_MAX;
return ZOMBIE_DAMAGE_MAX;
}
string pick_undead_voice_sound(const string &in undead_type) {
string pick_undead_voice_sound(const string& in undead_type) {
if (undead_type == "wight") {
int sound_index = random(0, undead_wight_sounds.length() - 1);
return undead_wight_sounds[sound_index];
@@ -54,10 +59,13 @@ string pick_undead_voice_sound(const string &in undead_type) {
return undead_zombie_sounds[sound_index];
}
string get_undead_label(const string &in undead_type) {
if (undead_type == "wight") return "wight";
if (undead_type == "vampyr") return "vampyr";
if (undead_type == "undead_resident") return "undead resident";
string get_undead_label(const string& in undead_type) {
if (undead_type == "wight")
return "wight";
if (undead_type == "vampyr")
return "vampyr";
if (undead_type == "undead_resident")
return "undead resident";
return "zombie";
}
@@ -87,8 +95,7 @@ class Undead {
move_timer.restart();
attack_timer.restart();
}
}
Undead@[] undeads;
} Undead @[] undeads;
int count_wights() {
int count = 0;
@@ -119,7 +126,8 @@ bool has_vampyr() {
}
int get_night_special_undead_spawn_limit(int day) {
if (day < 1) day = 1;
if (day < 1)
day = 1;
return 1 + (day / SPECIAL_UNDEAD_SPAWN_DAYS_PER_EXTRA);
}
@@ -131,12 +139,14 @@ void update_undead_weapon_range_audio() {
bool undead_range_audio_registered = false;
void ensure_undead_range_audio_registration() {
if (undead_range_audio_registered) return;
if (undead_range_audio_registered)
return;
undead_range_audio_registered = register_weapon_range_audio_callback(@update_undead_weapon_range_audio);
}
void clear_undeads() {
if (undeads.length() == 0) return;
if (undeads.length() == 0)
return;
for (uint i = 0; i < undeads.length(); i++) {
force_weapon_range_exit(undeads[i].position, undeads[i].in_weapon_range);
@@ -148,7 +158,7 @@ void clear_undeads() {
undeads.resize(0);
}
Undead@ get_undead_at(int pos) {
Undead @get_undead_at(int pos) {
for (uint i = 0; i < undeads.length(); i++) {
if (undeads[i].position == pos) {
return @undeads[i];
@@ -168,14 +178,18 @@ int pick_undead_spawn_position(int range_start, int range_end) {
for (int attempts = 0; attempts < 20; attempts++) {
int candidate = random(start, end);
if (candidate == x) continue;
if (get_undead_at(candidate) != null) continue;
if (candidate == x)
continue;
if (get_undead_at(candidate) != null)
continue;
return candidate;
}
for (int candidate = start; candidate <= end; candidate++) {
if (candidate == x) continue;
if (get_undead_at(candidate) != null) continue;
if (candidate == x)
continue;
if (get_undead_at(candidate) != null)
continue;
return candidate;
}
@@ -185,7 +199,8 @@ int pick_undead_spawn_position(int range_start, int range_end) {
int pick_undead_spawn_near_player(int min_distance, int max_distance) {
int min_dist = min_distance;
int max_dist = max_distance;
if (min_dist < 0) min_dist = 0;
if (min_dist < 0)
min_dist = 0;
if (max_dist < min_dist) {
int temp = min_dist;
min_dist = max_dist;
@@ -196,9 +211,12 @@ int pick_undead_spawn_near_player(int min_distance, int max_distance) {
int distance = random(min_dist, max_dist);
int direction = (random(0, 1) == 0) ? -1 : 1;
int candidate = x + (distance * direction);
if (candidate <= BASE_END || candidate < 0 || candidate >= MAP_SIZE) continue;
if (candidate == x) continue;
if (get_undead_at(candidate) != null) continue;
if (candidate <= BASE_END || candidate < 0 || candidate >= MAP_SIZE)
continue;
if (candidate == x)
continue;
if (get_undead_at(candidate) != null)
continue;
return candidate;
}
@@ -207,22 +225,30 @@ int pick_undead_spawn_near_player(int min_distance, int max_distance) {
int right_start = x + min_dist;
int right_end = x + max_dist;
if (left_start < BASE_END + 1) left_start = BASE_END + 1;
if (left_end < BASE_END + 1) left_end = BASE_END;
if (right_start < BASE_END + 1) right_start = BASE_END + 1;
if (left_start < BASE_END + 1)
left_start = BASE_END + 1;
if (left_end < BASE_END + 1)
left_end = BASE_END;
if (right_start < BASE_END + 1)
right_start = BASE_END + 1;
if (left_end >= MAP_SIZE) left_end = MAP_SIZE - 1;
if (right_start >= MAP_SIZE) right_start = MAP_SIZE;
if (right_end >= MAP_SIZE) right_end = MAP_SIZE - 1;
if (left_end >= MAP_SIZE)
left_end = MAP_SIZE - 1;
if (right_start >= MAP_SIZE)
right_start = MAP_SIZE;
if (right_end >= MAP_SIZE)
right_end = MAP_SIZE - 1;
int candidate = -1;
if (random(0, 1) == 0) {
if (left_start <= left_end) candidate = pick_undead_spawn_position(left_start, left_end);
if (left_start <= left_end)
candidate = pick_undead_spawn_position(left_start, left_end);
if (candidate == -1 && right_start <= right_end) {
candidate = pick_undead_spawn_position(right_start, right_end);
}
} else {
if (right_start <= right_end) candidate = pick_undead_spawn_position(right_start, right_end);
if (right_start <= right_end)
candidate = pick_undead_spawn_position(right_start, right_end);
if (candidate == -1 && left_start <= left_end) {
candidate = pick_undead_spawn_position(left_start, left_end);
}
@@ -231,7 +257,7 @@ int pick_undead_spawn_near_player(int min_distance, int max_distance) {
return candidate;
}
void spawn_undead(const string &in undead_type = "zombie") {
void spawn_undead(const string& in undead_type = "zombie") {
int spawn_x = -1;
if (undead_type == "zombie" || undead_type == "undead_resident") {
spawn_x = pick_undead_spawn_near_player(ZOMBIE_SPAWN_MIN_DISTANCE, ZOMBIE_SPAWN_MAX_DISTANCE);
@@ -239,9 +265,10 @@ void spawn_undead(const string &in undead_type = "zombie") {
if (spawn_x == -1) {
spawn_x = pick_undead_spawn_position(BASE_END + 1, MAP_SIZE - 1);
}
if (spawn_x == -1) return;
if (spawn_x == -1)
return;
Undead@ undead = Undead(spawn_x, undead_type);
Undead @undead = Undead(spawn_x, undead_type);
undeads.insert_last(undead);
// Play looping sound that follows the undead
int[] areaStarts;
@@ -252,18 +279,22 @@ void spawn_undead(const string &in undead_type = "zombie") {
if (undead_type == "vampyr") {
undead.voice_sound = pick_undead_voice_sound(undead_type);
}
undead.sound_handle = play_1d_with_volume_step(undead.voice_sound, x, spawn_x, loop_voice, ZOMBIE_SOUND_VOLUME_STEP);
undead.sound_handle =
play_1d_with_volume_step(undead.voice_sound, x, spawn_x, loop_voice, ZOMBIE_SOUND_VOLUME_STEP);
}
}
void try_attack_barricade_undead(Undead@ undead) {
if (barricade_health <= 0) return;
if (undead.attack_timer.elapsed < ZOMBIE_ATTACK_INTERVAL) return;
void try_attack_barricade_undead(Undead @undead) {
if (barricade_health <= 0)
return;
if (undead.attack_timer.elapsed < ZOMBIE_ATTACK_INTERVAL)
return;
undead.attack_timer.restart();
int damage = random(get_undead_damage_min(undead.undead_type), get_undead_damage_max(undead.undead_type));
barricade_health -= damage;
if (barricade_health < 0) barricade_health = 0;
if (barricade_health < 0)
barricade_health = 0;
play_creature_attack_sound("sounds/weapons/axe_hit.ogg", x, undead.position, ZOMBIE_SOUND_VOLUME_STEP);
@@ -284,7 +315,7 @@ void try_attack_barricade_undead(Undead@ undead) {
}
}
bool can_undead_attack_player(Undead@ undead) {
bool can_undead_attack_player(Undead @undead) {
if (player_health <= 0) {
return false;
}
@@ -308,7 +339,7 @@ bool can_undead_attack_player(Undead@ undead) {
return y <= ZOMBIE_ATTACK_MAX_HEIGHT;
}
bool try_attack_player_undead(Undead@ undead) {
bool try_attack_player_undead(Undead @undead) {
if (!can_undead_attack_player(undead)) {
return false;
}
@@ -327,7 +358,7 @@ bool try_attack_player_undead(Undead@ undead) {
return true;
}
void start_vampyr_retreat(Undead@ undead) {
void start_vampyr_retreat(Undead @undead) {
undead.retreating = true;
undead.suppress_voice = true;
if (undead.sound_handle != -1) {
@@ -337,7 +368,7 @@ void start_vampyr_retreat(Undead@ undead) {
undead.move_timer.restart();
}
void try_capture_resident_vampyr(Undead@ undead) {
void try_capture_resident_vampyr(Undead @undead) {
if (undead.attack_timer.elapsed < VAMPYR_CAPTURE_INTERVAL) {
return;
}
@@ -350,14 +381,15 @@ void try_capture_resident_vampyr(Undead@ undead) {
if (random(1, 100) <= VAMPYR_CAPTURE_CHANCE) {
residents_count--;
if (residents_count < 0) residents_count = 0;
if (residents_count < 0)
residents_count = 0;
undead_residents_pending++;
speak_with_history("A resident has been taken.", true);
start_vampyr_retreat(undead);
}
}
void update_undead(Undead@ undead, bool audio_active) {
void update_undead(Undead @undead, bool audio_active) {
bool is_vampyr = (undead.undead_type == "vampyr");
bool loop_voice = !is_vampyr;
@@ -377,19 +409,22 @@ void update_undead(Undead@ undead, bool audio_active) {
if (is_vampyr) {
undead.voice_sound = pick_undead_voice_sound(undead.undead_type);
}
undead.sound_handle = play_1d_with_volume_step(undead.voice_sound, x, undead.position, loop_voice, ZOMBIE_SOUND_VOLUME_STEP);
undead.sound_handle =
play_1d_with_volume_step(undead.voice_sound, x, undead.position, loop_voice, ZOMBIE_SOUND_VOLUME_STEP);
}
if (try_attack_player_undead(undead)) {
return;
}
if (undead.undead_type == "vampyr" && !undead.retreating && barricade_health > 0 && undead.position == BASE_END + 1) {
if (undead.undead_type == "vampyr" && !undead.retreating && barricade_health > 0 &&
undead.position == BASE_END + 1) {
try_capture_resident_vampyr(undead);
return;
}
if (undead.move_timer.elapsed < ZOMBIE_MOVE_INTERVAL) return;
if (undead.move_timer.elapsed < ZOMBIE_MOVE_INTERVAL)
return;
undead.move_timer.restart();
if (undead.undead_type != "vampyr" && barricade_health > 0 && undead.position == BASE_END + 1) {
@@ -433,12 +468,14 @@ void update_undead(Undead@ undead, bool audio_active) {
}
} else {
direction = random(-1, 1);
if (direction == 0) return;
if (direction == 0)
return;
}
}
int target_x = undead.position + direction;
if (target_x < 0 || target_x >= MAP_SIZE) return;
if (target_x < 0 || target_x >= MAP_SIZE)
return;
if (undead.undead_type != "vampyr" && target_x <= BASE_END && barricade_health > 0) {
try_attack_barricade_undead(undead);
@@ -447,7 +484,8 @@ void update_undead(Undead@ undead, bool audio_active) {
undead.position = target_x;
if (audio_active) {
play_creature_footstep(x, undead.position, BASE_END, GRASS_END, ZOMBIE_FOOTSTEP_MAX_DISTANCE, ZOMBIE_SOUND_VOLUME_STEP);
play_creature_footstep(x, undead.position, BASE_END, GRASS_END, ZOMBIE_FOOTSTEP_MAX_DISTANCE,
ZOMBIE_SOUND_VOLUME_STEP);
}
}
@@ -478,7 +516,8 @@ void update_undeads() {
if (zombie_swarm_active) {
maxCount += ZOMBIE_SWARM_ZOMBIE_MAX_BONUS;
}
if (maxCount > ZOMBIE_MAX_COUNT_CAP) maxCount = ZOMBIE_MAX_COUNT_CAP;
if (maxCount > ZOMBIE_MAX_COUNT_CAP)
maxCount = ZOMBIE_MAX_COUNT_CAP;
int zombie_count = 0;
int undead_resident_count = 0;
@@ -508,7 +547,8 @@ void update_undeads() {
bool limit_audio = (areaStarts.length() > 0);
for (uint i = 0; i < undeads.length(); i++) {
bool audio_active = !limit_audio || range_overlaps_active_areas(undeads[i].position, undeads[i].position, areaStarts, areaEnds);
bool audio_active =
!limit_audio || range_overlaps_active_areas(undeads[i].position, undeads[i].position, areaStarts, areaEnds);
update_undead(undeads[i], audio_active);
}
@@ -555,7 +595,8 @@ void attempt_hourly_wight_spawn() {
}
wight_spawn_chance += WIGHT_SPAWN_CHANCE_STEP;
if (wight_spawn_chance > 100) wight_spawn_chance = 100;
if (wight_spawn_chance > 100)
wight_spawn_chance = 100;
}
void attempt_hourly_vampyr_spawn() {
@@ -594,7 +635,8 @@ void attempt_hourly_vampyr_spawn() {
}
vampyr_spawn_chance += VAMPYR_SPAWN_CHANCE_STEP;
if (vampyr_spawn_chance > 100) vampyr_spawn_chance = 100;
if (vampyr_spawn_chance > 100)
vampyr_spawn_chance = 100;
}
bool damage_undead_at(int pos, int damage) {
@@ -607,13 +649,15 @@ bool damage_undead_at(int pos, int damage) {
}
if (undeads[i].undead_type == "undead_resident") {
undead_residents_count--;
if (undead_residents_count < 0) undead_residents_count = 0;
if (undead_residents_count < 0)
undead_residents_count = 0;
}
if (undeads[i].sound_handle != -1) {
p.destroy_sound(undeads[i].sound_handle);
undeads[i].sound_handle = -1;
}
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", undeads[i].voice_sound, x, pos, ZOMBIE_SOUND_VOLUME_STEP);
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", undeads[i].voice_sound, x, pos,
ZOMBIE_SOUND_VOLUME_STEP);
undeads.remove_at(i);
}
return true;
@@ -623,9 +667,19 @@ bool damage_undead_at(int pos, int damage) {
}
// Backward compatibility aliases (to be removed after full refactoring)
Undead@[]@ zombies = @undeads; // Array alias for backward compatibility
Undead@ get_zombie_at(int pos) { return get_undead_at(pos); }
bool damage_zombie_at(int pos, int damage) { return damage_undead_at(pos, damage); }
void update_zombies() { update_undeads(); }
void clear_zombies() { clear_undeads(); }
void spawn_zombie() { spawn_undead("zombie"); }
Undead @[] @zombies = @undeads; // Array alias for backward compatibility
Undead @get_zombie_at(int pos) {
return get_undead_at(pos);
}
bool damage_zombie_at(int pos, int damage) {
return damage_undead_at(pos, damage);
}
void update_zombies() {
update_undeads();
}
void clear_zombies() {
clear_undeads();
}
void spawn_zombie() {
spawn_undead("zombie");
}
+128 -100
View File
@@ -8,7 +8,6 @@ void apply_falling_damage(int fall_height) {
p.play_stationary("sounds/actions/hit_ground.ogg", false);
if (fall_height <= SAFE_FALL_HEIGHT) {
speak_with_history("Landed safely.", true);
return;
}
@@ -20,13 +19,15 @@ void apply_falling_damage(int fall_height) {
// Apply damage
player_health -= damage;
if (player_health < 0) player_health = 0;
if (player_health < 0)
player_health = 0;
if (damage > 0) {
play_player_damage_sound();
}
// Feedback
speak_with_history("Fell " + fall_height + " feet! Took " + damage + " damage. " + player_health + " health remaining.", true);
speak_with_history(
"Fell " + fall_height + " feet! Took " + damage + " damage. " + player_health + " health remaining.", true);
}
// Tree Object
class Tree {
@@ -74,7 +75,7 @@ class Tree {
areaEnd = GRASS_END;
}
Tree@ currentTree = @this;
Tree @currentTree = @ this;
if (!place_tree_in_area(currentTree, areaStart, areaEnd)) {
return;
}
@@ -111,10 +112,12 @@ class Tree {
void try_regen() {
// Skip if tree is fully stocked
if (!depleted && !is_chopped) return;
if (!depleted && !is_chopped)
return;
// Check every minute (60000ms)
if (regen_timer.elapsed < 60000) return;
if (regen_timer.elapsed < 60000)
return;
// Advance to next minute
regen_timer.restart();
@@ -142,16 +145,21 @@ class Tree {
// Determine base chance based on minutes elapsed
int base_chance = 0;
if (minutes_since_depletion == 1) base_chance = 25;
else if (minutes_since_depletion == 2) base_chance = 50;
else if (minutes_since_depletion == 3) base_chance = 75;
else if (minutes_since_depletion == 4) base_chance = 100;
if (minutes_since_depletion == 1)
base_chance = 25;
else if (minutes_since_depletion == 2)
base_chance = 50;
else if (minutes_since_depletion == 3)
base_chance = 75;
else if (minutes_since_depletion == 4)
base_chance = 100;
// Try to add items with decreasing probability
int current_chance = base_chance;
while (current_chance >= 25) {
// Check if we can add anything
if (sticks >= 3 && vines >= 2) break;
if (sticks >= 3 && vines >= 2)
break;
// Roll for success
int roll = random(1, 100);
@@ -183,8 +191,7 @@ class Tree {
is_chopped = false;
}
}
}
Tree@[] trees;
} Tree @[] trees;
const int SEARCH_POOL_STREAM_BANK = 0;
const int SEARCH_POOL_FOREST = 1;
@@ -198,7 +205,7 @@ class SearchPool {
string[] terrain_tags;
}
SearchPool@[] search_pools;
SearchPool @[] search_pools;
int[] search_mass_noun_items;
void init_search_pools() {
@@ -209,26 +216,26 @@ void init_search_pools() {
search_pools.resize(SEARCH_POOL_COUNT);
@search_pools[SEARCH_POOL_STREAM_BANK] = SearchPool();
search_pools[SEARCH_POOL_STREAM_BANK].item_types = { ITEM_REEDS, ITEM_CLAY };
search_pools[SEARCH_POOL_STREAM_BANK].weights = { 30, 70 };
search_pools[SEARCH_POOL_STREAM_BANK].found_messages = { "Found a reed.", "Found clay." };
search_pools[SEARCH_POOL_STREAM_BANK].terrain_tags = { "stream_bank" };
search_pools[SEARCH_POOL_STREAM_BANK].item_types = {ITEM_REEDS, ITEM_CLAY};
search_pools[SEARCH_POOL_STREAM_BANK].weights = {30, 70};
search_pools[SEARCH_POOL_STREAM_BANK].found_messages = {"Found a reed.", "Found clay."};
search_pools[SEARCH_POOL_STREAM_BANK].terrain_tags = {"stream_bank"};
@search_pools[SEARCH_POOL_FOREST] = SearchPool();
search_pools[SEARCH_POOL_FOREST].item_types = { ITEM_STICKS, ITEM_VINES };
search_pools[SEARCH_POOL_FOREST].weights = { 1, 1 };
search_pools[SEARCH_POOL_FOREST].found_messages = { "Found a stick.", "Found a vine." };
search_pools[SEARCH_POOL_FOREST].terrain_tags = { "forest", "deep_forest" };
search_pools[SEARCH_POOL_FOREST].item_types = {ITEM_STICKS, ITEM_VINES};
search_pools[SEARCH_POOL_FOREST].weights = {1, 1};
search_pools[SEARCH_POOL_FOREST].found_messages = {"Found a stick.", "Found a vine."};
search_pools[SEARCH_POOL_FOREST].terrain_tags = {"forest", "deep_forest"};
@search_pools[SEARCH_POOL_STONE_TERRAIN] = SearchPool();
search_pools[SEARCH_POOL_STONE_TERRAIN].item_types = { ITEM_STONES };
search_pools[SEARCH_POOL_STONE_TERRAIN].weights = { 1 };
search_pools[SEARCH_POOL_STONE_TERRAIN].found_messages = { "Found a stone." };
search_pools[SEARCH_POOL_STONE_TERRAIN].terrain_tags = { "gravel", "stone", "hard_stone" };
search_pools[SEARCH_POOL_STONE_TERRAIN].item_types = {ITEM_STONES};
search_pools[SEARCH_POOL_STONE_TERRAIN].weights = {1};
search_pools[SEARCH_POOL_STONE_TERRAIN].found_messages = {"Found a stone."};
search_pools[SEARCH_POOL_STONE_TERRAIN].terrain_tags = {"gravel", "stone", "hard_stone"};
// Mass nouns for auto "Found X." fallback (no article).
// Add new mass nouns here when adding search items that should not use "a/an".
search_mass_noun_items = { ITEM_CLAY };
search_mass_noun_items = {ITEM_CLAY};
}
string get_tree_area_terrain(int areaStart, int areaEnd) {
@@ -258,7 +265,7 @@ int get_tree_max_for_area(int areaStart, int areaEnd) {
return TREE_MAX_PER_AREA;
}
bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out areaEnd, string &out areaTerrain) {
bool get_tree_area_bounds_for_position(int pos, int& out areaStart, int& out areaEnd, string& out areaTerrain) {
if (pos >= BASE_END + 1 && pos <= GRASS_END) {
areaStart = BASE_END + 1;
areaEnd = GRASS_END;
@@ -271,12 +278,14 @@ bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out are
}
int index = pos - expanded_area_start;
if (index < 0 || index >= int(expanded_terrain_types.length())) return false;
if (index < 0 || index >= int(expanded_terrain_types.length()))
return false;
string terrain = expanded_terrain_types[index];
if (terrain.find("mountain:") == 0) {
terrain = terrain.substr(9);
}
if (terrain != "grass" && terrain != "forest" && terrain != "deep_forest") return false;
if (terrain != "grass" && terrain != "forest" && terrain != "deep_forest")
return false;
int left = index;
while (left > 0) {
@@ -284,7 +293,8 @@ bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out are
if (leftTerrain.find("mountain:") == 0) {
leftTerrain = leftTerrain.substr(9);
}
if (leftTerrain != terrain) break;
if (leftTerrain != terrain)
break;
left--;
}
@@ -295,7 +305,8 @@ bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out are
if (rightTerrain.find("mountain:") == 0) {
rightTerrain = rightTerrain.substr(9);
}
if (rightTerrain != terrain) break;
if (rightTerrain != terrain)
break;
right++;
}
@@ -305,10 +316,11 @@ bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out are
return true;
}
int count_trees_in_area(int areaStart, int areaEnd, Tree@ ignoreTree) {
int count_trees_in_area(int areaStart, int areaEnd, Tree @ignoreTree) {
int count = 0;
for (uint i = 0; i < trees.length(); i++) {
if (@trees[i] is ignoreTree) continue;
if (@trees[i] is ignoreTree)
continue;
if (trees[i].position >= areaStart && trees[i].position <= areaEnd) {
count++;
}
@@ -317,16 +329,19 @@ int count_trees_in_area(int areaStart, int areaEnd, Tree@ ignoreTree) {
}
bool is_near_required_climb(int pos, int radius) {
MountainRange@ mountain = get_mountain_at(pos);
if (mountain is null) return false;
MountainRange @mountain = get_mountain_at(pos);
if (mountain is null)
return false;
int startPos = mountain.start_position;
int endPos = mountain.end_position;
int edgeStart = pos - radius - 1;
int edgeEnd = pos + radius;
if (edgeStart < startPos) edgeStart = startPos;
if (edgeEnd > endPos - 1) edgeEnd = endPos - 1;
if (edgeStart < startPos)
edgeStart = startPos;
if (edgeEnd > endPos - 1)
edgeEnd = endPos - 1;
for (int xPos = edgeStart; xPos <= edgeEnd; xPos++) {
if (mountain.is_steep_section(xPos, xPos + 1)) {
@@ -337,7 +352,7 @@ bool is_near_required_climb(int pos, int radius) {
return false;
}
bool tree_too_close_in_area(int pos, int areaStart, int areaEnd, Tree@ ignoreTree) {
bool tree_too_close_in_area(int pos, int areaStart, int areaEnd, Tree @ignoreTree) {
// Keep trees away from the base edge
if (pos < BASE_END + 5) {
return true;
@@ -348,8 +363,10 @@ bool tree_too_close_in_area(int pos, int areaStart, int areaEnd, Tree@ ignoreTre
}
for (uint i = 0; i < trees.length(); i++) {
if (@trees[i] is ignoreTree) continue;
if (trees[i].position < areaStart || trees[i].position > areaEnd) continue;
if (@trees[i] is ignoreTree)
continue;
if (trees[i].position < areaStart || trees[i].position > areaEnd)
continue;
if (abs(trees[i].position - pos) < TREE_MIN_DISTANCE) {
return true;
@@ -358,7 +375,7 @@ bool tree_too_close_in_area(int pos, int areaStart, int areaEnd, Tree@ ignoreTre
return false;
}
bool place_tree_in_area(Tree@ tree, int areaStart, int areaEnd) {
bool place_tree_in_area(Tree @tree, int areaStart, int areaEnd) {
int maxTrees = get_tree_max_for_area(areaStart, areaEnd);
if (count_trees_in_area(areaStart, areaEnd, tree) >= maxTrees) {
return false;
@@ -388,7 +405,7 @@ bool spawn_tree_in_area(int areaStart, int areaEnd) {
if (tree_too_close_in_area(pos, areaStart, areaEnd, null)) {
continue;
}
Tree@ t = Tree(pos);
Tree @t = Tree(pos);
trees.insert_last(t);
return true;
}
@@ -401,14 +418,15 @@ void spawn_trees(int grass_start, int grass_end) {
}
}
void get_tree_areas(int[]@ areaStarts, int[]@ areaEnds) {
void get_tree_areas(int[] @areaStarts, int[] @areaEnds) {
areaStarts.resize(0);
areaEnds.resize(0);
areaStarts.insert_last(BASE_END + 1);
areaEnds.insert_last(GRASS_END);
if (expanded_area_start == -1) return;
if (expanded_area_start == -1)
return;
int total = int(expanded_terrain_types.length());
int index = 0;
while (index < total) {
@@ -423,7 +441,8 @@ void get_tree_areas(int[]@ areaStarts, int[]@ areaEnds) {
if (nextTerrain.find("mountain:") == 0) {
nextTerrain = nextTerrain.substr(9);
}
if (nextTerrain != terrain) break;
if (nextTerrain != terrain)
break;
index++;
}
int segmentEnd = index;
@@ -434,10 +453,11 @@ void get_tree_areas(int[]@ areaStarts, int[]@ areaEnds) {
}
}
bool relocate_tree_to_any_area(Tree@ tree, int[]@ areaStarts, int[]@ areaEnds) {
bool relocate_tree_to_any_area(Tree @tree, int[] @areaStarts, int[] @areaEnds) {
for (uint i = 0; i < areaStarts.length(); i++) {
int maxTrees = get_tree_max_for_area(areaStarts[i], areaEnds[i]);
if (count_trees_in_area(areaStarts[i], areaEnds[i], tree) >= maxTrees) continue;
if (count_trees_in_area(areaStarts[i], areaEnds[i], tree) >= maxTrees)
continue;
if (place_tree_in_area(tree, areaStarts[i], areaEnds[i])) {
return true;
}
@@ -449,7 +469,8 @@ void normalize_tree_positions() {
int[] areaStarts;
int[] areaEnds;
get_tree_areas(areaStarts, areaEnds);
if (areaStarts.length() == 0) return;
if (areaStarts.length() == 0)
return;
for (uint i = 0; i < trees.length(); i++) {
int areaStart = 0;
@@ -480,7 +501,7 @@ void normalize_tree_positions() {
while (areaTreeIndices.length() > maxTrees) {
uint treeIndex = areaTreeIndices[areaTreeIndices.length() - 1];
Tree@ tree = trees[treeIndex];
Tree @tree = trees[treeIndex];
if (!relocate_tree_to_any_area(tree, areaStarts, areaEnds)) {
if (tree.sound_handle != -1) {
p.destroy_sound(tree.sound_handle);
@@ -497,8 +518,8 @@ void normalize_tree_positions() {
}
if (areaTreeIndices.length() == 2) {
Tree@ firstTree = trees[areaTreeIndices[0]];
Tree@ secondTree = trees[areaTreeIndices[1]];
Tree @firstTree = trees[areaTreeIndices[0]];
Tree @secondTree = trees[areaTreeIndices[1]];
if (abs(firstTree.position - secondTree.position) < TREE_MIN_DISTANCE) {
if (!place_tree_in_area(secondTree, areaStart, areaEnd)) {
place_tree_in_area(firstTree, areaStart, areaEnd);
@@ -514,7 +535,7 @@ void update_environment() {
get_active_audio_areas(areaStarts, areaEnds);
bool limit_audio = (areaStarts.length() > 0);
for(uint i = 0; i < trees.length(); i++) {
for (uint i = 0; i < trees.length(); i++) {
trees[i].try_regen();
if (limit_audio && !range_overlaps_active_areas(trees[i].position, trees[i].position, areaStarts, areaEnds)) {
@@ -528,9 +549,9 @@ void update_environment() {
}
}
Tree@ get_tree_at(int target_x) {
for(uint i=0; i<trees.length(); i++) {
if(trees[i].position == target_x) {
Tree @get_tree_at(int target_x) {
for (uint i = 0; i < trees.length(); i++) {
if (trees[i].position == target_x) {
return @trees[i];
}
}
@@ -538,20 +559,20 @@ Tree@ get_tree_at(int target_x) {
}
void damage_tree(int target_x, int damage) {
Tree@ target = null;
for(uint i=0; i<trees.length(); i++) {
if(trees[i].position == target_x) {
Tree @target = null;
for (uint i = 0; i < trees.length(); i++) {
if (trees[i].position == target_x) {
@target = @trees[i];
break;
}
}
if(@target != null) {
if(!target.is_chopped) {
if (@target != null) {
if (!target.is_chopped) {
target.health -= damage;
p.play_stationary("sounds/weapons/axe_hit.ogg", false);
if(target.health <= 0) {
if (target.health <= 0) {
target.is_chopped = true;
target.depleted = true;
target.regen_timer.restart();
@@ -578,7 +599,8 @@ void damage_tree(int target_x, int damage) {
string drop_message = "Tree fell!";
if (sticks_added > 0 || vines_added > 0 || logs_added > 0) {
string log_label = (logs_added == 1) ? " log" : " logs";
drop_message += " Got " + sticks_added + " sticks, " + vines_added + " vines, and " + logs_added + log_label + ".";
drop_message += " Got " + sticks_added + " sticks, " + vines_added + " vines, and " + logs_added +
log_label + ".";
}
if (sticks_added < sticks_dropped || vines_added < vines_dropped || logs_added < 1) {
drop_message += " Inventory full.";
@@ -626,7 +648,8 @@ string get_auto_found_message(int item_type) {
}
string first_letter = singular.substr(0, 1);
if (first_letter == "a" || first_letter == "e" || first_letter == "i" || first_letter == "o" || first_letter == "u") {
if (first_letter == "a" || first_letter == "e" || first_letter == "i" || first_letter == "o" ||
first_letter == "u") {
return "Found an " + singular + ".";
}
return "Found a " + singular + ".";
@@ -698,19 +721,18 @@ bool try_search_for_terrain(string terrain_type) {
}
for (uint j = 0; j < search_pools[i].terrain_tags.length(); j++) {
if (search_pools[i].terrain_tags[j] == terrain_type) {
return try_find_weighted_resource(search_pools[i].item_types,
search_pools[i].weights, search_pools[i].found_messages);
return try_find_weighted_resource(search_pools[i].item_types, search_pools[i].weights,
search_pools[i].found_messages);
}
}
}
return false;
}
void perform_search(int current_x)
{
void perform_search(int current_x) {
// First priority: Check for world drops on this tile or adjacent
for (int check_x = current_x - 1; check_x <= current_x + 1; check_x++) {
WorldDrop@ drop = get_drop_at(check_x);
WorldDrop @drop = get_drop_at(check_x);
if (drop != null) {
if (!try_pickup_world_drop(drop)) {
return;
@@ -725,13 +747,14 @@ void perform_search(int current_x)
for (int check_x = current_x - SNARE_COLLECT_RANGE; check_x <= current_x + SNARE_COLLECT_RANGE; check_x++) {
// Skip current x? User said "beside". If on top, it breaks.
// But if I stand adjacent and shift...
if (check_x == current_x) continue; // Safety against collecting own snare you stand on? (Collision happens on move)
if (check_x == current_x)
continue; // Safety against collecting own snare you stand on? (Collision happens on move)
// Actually, collision happens when *moving onto* it. If you placed it, you are on it.
// If active is false (just placed), you can pick it up.
// If active is true (you moved away), moving back breaks it.
// So checking adjacent is correct.
WorldSnare@ s = get_snare_at(check_x);
WorldSnare @s = get_snare_at(check_x);
if (s != null) {
if (s.has_catch) {
if (get_personal_count(ITEM_SMALL_GAME) >= get_personal_stack_limit()) {
@@ -791,7 +814,8 @@ void perform_search(int current_x)
break;
}
}
if (near_stream_bank) break;
if (near_stream_bank)
break;
}
}
@@ -803,17 +827,15 @@ void perform_search(int current_x)
// Trees (Sticks/Vines) - Check for nearby tree, but only on non-stone terrain
// Skip tree search if player is on stone terrain (prioritize stone finding)
string search_terrain = get_terrain_at_position(current_x);
bool skip_tree_search = (search_terrain == "stone" || search_terrain == "gravel" ||
search_terrain == "snow" || search_terrain == "hard_stone");
bool skip_tree_search = (search_terrain == "stone" || search_terrain == "gravel" || search_terrain == "snow" ||
search_terrain == "hard_stone");
Tree@ nearest = null;
Tree @nearest = null;
int nearest_distance = 999;
if (!skip_tree_search) {
for(uint i=0; i<trees.length(); i++)
{
for (uint i = 0; i < trees.length(); i++) {
int distance = abs(trees[i].position - current_x);
if(distance <= 1 && distance < nearest_distance)
{
if (distance <= 1 && distance < nearest_distance) {
nearest_distance = distance;
@nearest = @trees[i];
if (nearest_distance == 0) {
@@ -823,9 +845,8 @@ void perform_search(int current_x)
}
}
if(@nearest != null)
{
if(nearest.is_chopped) {
if (@nearest != null) {
if (nearest.is_chopped) {
speak_with_history("This tree has been cut down.", true);
return;
}
@@ -835,8 +856,7 @@ void perform_search(int current_x)
return;
}
if(nearest.sticks > 0 || nearest.vines > 0)
{
if (nearest.sticks > 0 || nearest.vines > 0) {
bool find_stick = (nearest.vines <= 0) || (nearest.sticks > 0 && random(0, 1) == 0);
bool took_item = false;
@@ -881,14 +901,12 @@ void perform_search(int current_x)
return;
}
if(nearest.sticks == 0 && nearest.vines == 0) {
if (nearest.sticks == 0 && nearest.vines == 0) {
nearest.depleted = true;
nearest.regen_timer.restart();
nearest.minutes_since_depletion = 0;
}
}
else
{
} else {
speak_with_history("This area has nothing left.", true);
}
return;
@@ -903,7 +921,7 @@ void perform_search(int current_x)
// Climbing functions
void start_climbing_tree(int target_x) {
Tree@ tree = get_tree_at(target_x);
Tree @tree = get_tree_at(target_x);
if (tree == null || tree.is_chopped) {
return;
}
@@ -916,7 +934,8 @@ void start_climbing_tree(int target_x) {
}
void update_climbing() {
if (!climbing) return;
if (!climbing)
return;
if (y == climb_target_y) {
climbing = false;
return;
@@ -955,7 +974,8 @@ void update_climbing() {
void climb_down_tree() {
int ground_elevation = get_mountain_elevation_at(x);
if (y == ground_elevation || climbing) return;
if (y == ground_elevation || climbing)
return;
climbing = true;
climb_target_y = ground_elevation;
@@ -964,7 +984,8 @@ void climb_down_tree() {
}
void start_falling() {
if (y <= 0 || falling) return;
if (y <= 0 || falling)
return;
falling = true;
fall_start_y = y; // Remember where we started falling from
@@ -975,7 +996,8 @@ void start_falling() {
}
void update_falling() {
if (!falling) return;
if (!falling)
return;
// Get ground level (mountain elevation or 0)
int ground_level = get_mountain_elevation_at(x);
@@ -995,8 +1017,10 @@ void update_falling() {
// Pitch ranges from 100 (high up) to 50 (near ground)
float height_above_ground = float(y - ground_level);
float pitch_percent = 50.0 + (50.0 * (height_above_ground / 30.0));
if (pitch_percent < 50.0) pitch_percent = 50.0;
if (pitch_percent > 100.0) pitch_percent = 100.0;
if (pitch_percent < 50.0)
pitch_percent = 50.0;
if (pitch_percent > 100.0)
pitch_percent = 100.0;
fall_sound_handle = p.play_stationary_extended("sounds/actions/falling.ogg", true, 0, 0, 0, pitch_percent);
@@ -1028,7 +1052,7 @@ void land_on_ground(int ground_level) {
// Mountain movement check
bool can_move_mountain(int from_x, int to_x) {
MountainRange@ mountain = get_mountain_at(to_x);
MountainRange @mountain = get_mountain_at(to_x);
if (mountain is null) {
// Not entering a mountain
return true;
@@ -1066,8 +1090,10 @@ bool can_move_mountain(int from_x, int to_x) {
}
bool can_enter_stream_tile(int pos) {
if (!is_deep_stream_at(pos)) return true;
if (get_personal_count(ITEM_CANOES) > 0) return true;
if (!is_deep_stream_at(pos))
return true;
if (get_personal_count(ITEM_CANOES) > 0)
return true;
speak_movement_blocked("You need a canoe to cross deep water.");
return false;
}
@@ -1116,7 +1142,8 @@ void start_rope_climb(bool climbing_up, int target_x, int target_elevation) {
}
void update_rope_climbing() {
if (!rope_climbing) return;
if (!rope_climbing)
return;
// Check if we're already at the target (shouldn't happen, but safety check)
if (y == rope_climb_target_y) {
@@ -1168,7 +1195,8 @@ void complete_rope_climb() {
}
void check_rope_climb_fall() {
if (!rope_climbing) return;
if (!rope_climbing)
return;
if (key_down(KEY_LEFT) || key_down(KEY_RIGHT)) {
rope_climb_sound_handle = -1;
+67 -36
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -103,15 +103,20 @@ void init_item_registry() {
item_registry[ITEM_AXES] = ItemDefinition(ITEM_AXES, "axes", "axe", "Axes", 1.50);
item_registry[ITEM_SNARES] = ItemDefinition(ITEM_SNARES, "snares", "snare", "Snares", 0.50);
item_registry[ITEM_KNIVES] = ItemDefinition(ITEM_KNIVES, "knives", "knife", "Knives", 0.80);
item_registry[ITEM_FISHING_POLES] = ItemDefinition(ITEM_FISHING_POLES, "fishing poles", "fishing pole", "Fishing Poles", 0.80);
item_registry[ITEM_FISHING_POLES] =
ItemDefinition(ITEM_FISHING_POLES, "fishing poles", "fishing pole", "Fishing Poles", 0.80);
item_registry[ITEM_SKIN_HATS] = ItemDefinition(ITEM_SKIN_HATS, "skin hats", "skin hat", "Skin Hats", 0.60);
item_registry[ITEM_SKIN_GLOVES] = ItemDefinition(ITEM_SKIN_GLOVES, "skin gloves", "skin glove", "Skin Gloves", 0.60);
item_registry[ITEM_SKIN_GLOVES] =
ItemDefinition(ITEM_SKIN_GLOVES, "skin gloves", "skin glove", "Skin Gloves", 0.60);
item_registry[ITEM_SKIN_PANTS] = ItemDefinition(ITEM_SKIN_PANTS, "skin pants", "skin pants", "Skin Pants", 1.20);
item_registry[ITEM_SKIN_TUNICS] = ItemDefinition(ITEM_SKIN_TUNICS, "skin tunics", "skin tunic", "Skin Tunics", 1.20);
item_registry[ITEM_SKIN_TUNICS] =
ItemDefinition(ITEM_SKIN_TUNICS, "skin tunics", "skin tunic", "Skin Tunics", 1.20);
item_registry[ITEM_MOCCASINS] = ItemDefinition(ITEM_MOCCASINS, "moccasins", "moccasin", "Moccasins", 0.80);
item_registry[ITEM_SKIN_POUCHES] = ItemDefinition(ITEM_SKIN_POUCHES, "skin pouches", "skin pouch", "Skin Pouches", 0.80);
item_registry[ITEM_SKIN_POUCHES] =
ItemDefinition(ITEM_SKIN_POUCHES, "skin pouches", "skin pouch", "Skin Pouches", 0.80);
item_registry[ITEM_ROPES] = ItemDefinition(ITEM_ROPES, "ropes", "rope", "Ropes", 0.40);
item_registry[ITEM_REED_BASKETS] = ItemDefinition(ITEM_REED_BASKETS, "reed baskets", "reed basket", "Reed Baskets", 0.60);
item_registry[ITEM_REED_BASKETS] =
ItemDefinition(ITEM_REED_BASKETS, "reed baskets", "reed basket", "Reed Baskets", 0.60);
item_registry[ITEM_CLAY_POTS] = ItemDefinition(ITEM_CLAY_POTS, "clay pots", "clay pot", "Clay Pots", 0.70);
item_registry[ITEM_FEATHERS] = ItemDefinition(ITEM_FEATHERS, "feathers", "feather", "Feathers", 0.05);
item_registry[ITEM_DOWN] = ItemDefinition(ITEM_DOWN, "down", "down", "Down", 0.05);
@@ -121,64 +126,36 @@ void init_item_registry() {
item_registry[ITEM_QUIVERS] = ItemDefinition(ITEM_QUIVERS, "quivers", "quiver", "Quivers", 1.50);
item_registry[ITEM_BOWSTRINGS] = ItemDefinition(ITEM_BOWSTRINGS, "bowstrings", "bowstring", "Bowstrings", 0.20);
item_registry[ITEM_SINEW] = ItemDefinition(ITEM_SINEW, "sinew", "piece of sinew", "Sinew", 0.10);
item_registry[ITEM_BOAR_CARCASSES] = ItemDefinition(ITEM_BOAR_CARCASSES, "boar carcasses", "boar carcass", "Boar Carcasses", 1.50);
item_registry[ITEM_BOAR_CARCASSES] =
ItemDefinition(ITEM_BOAR_CARCASSES, "boar carcasses", "boar carcass", "Boar Carcasses", 1.50);
item_registry[ITEM_BACKPACKS] = ItemDefinition(ITEM_BACKPACKS, "backpacks", "backpack", "Backpacks", 2.50);
item_registry[ITEM_CANOES] = ItemDefinition(ITEM_CANOES, "canoes", "canoe", "Canoes", 4.00);
item_registry[ITEM_FISH] = ItemDefinition(ITEM_FISH, "fish", "fish", "Fish", 0.10);
item_registry[ITEM_SMOKED_FISH] = ItemDefinition(ITEM_SMOKED_FISH, "smoked fish", "smoked fish", "Smoked Fish", 0.20);
item_registry[ITEM_HEAL_SCROLL] = ItemDefinition(ITEM_HEAL_SCROLL, "heal scrolls", "heal scroll", "Heal Scrolls", 0.50);
item_registry[ITEM_BASKET_FOOD] = ItemDefinition(ITEM_BASKET_FOOD, "baskets of fruits and nuts", "basket of fruits and nuts", "Baskets of Fruits and Nuts", 0.15);
item_registry[ITEM_SMOKED_FISH] =
ItemDefinition(ITEM_SMOKED_FISH, "smoked fish", "smoked fish", "Smoked Fish", 0.20);
item_registry[ITEM_HEAL_SCROLL] =
ItemDefinition(ITEM_HEAL_SCROLL, "heal scrolls", "heal scroll", "Heal Scrolls", 0.50);
item_registry[ITEM_BASKET_FOOD] = ItemDefinition(ITEM_BASKET_FOOD, "baskets of fruits and nuts",
"basket of fruits and nuts", "Baskets of Fruits and Nuts", 0.15);
// Define display order for inventory menus
// This controls the order items appear in menus
inventory_display_order = {
// Raw materials
ITEM_STICKS,
ITEM_VINES,
ITEM_REEDS,
ITEM_STONES,
ITEM_LOGS,
ITEM_CLAY,
ITEM_STICKS, ITEM_VINES, ITEM_REEDS, ITEM_STONES, ITEM_LOGS, ITEM_CLAY,
// Hunting drops
ITEM_SMALL_GAME,
ITEM_BOAR_CARCASSES,
ITEM_MEAT,
ITEM_SKINS,
ITEM_FEATHERS,
ITEM_DOWN,
ITEM_SINEW,
ITEM_SMALL_GAME, ITEM_BOAR_CARCASSES, ITEM_MEAT, ITEM_SKINS, ITEM_FEATHERS, ITEM_DOWN, ITEM_SINEW,
// Food items
ITEM_FISH,
ITEM_SMOKED_FISH,
ITEM_BASKET_FOOD,
ITEM_FISH, ITEM_SMOKED_FISH, ITEM_BASKET_FOOD,
// Misc items
ITEM_INCENSE,
ITEM_HEAL_SCROLL,
ITEM_INCENSE, ITEM_HEAL_SCROLL,
// Weapons
ITEM_SPEARS,
ITEM_SLINGS,
ITEM_AXES,
ITEM_BOWS,
ITEM_ARROWS,
ITEM_QUIVERS,
ITEM_BOWSTRINGS,
ITEM_SPEARS, ITEM_SLINGS, ITEM_AXES, ITEM_BOWS, ITEM_ARROWS, ITEM_QUIVERS, ITEM_BOWSTRINGS,
// Tools
ITEM_SNARES,
ITEM_KNIVES,
ITEM_FISHING_POLES,
ITEM_ROPES,
ITEM_REED_BASKETS,
ITEM_CLAY_POTS,
ITEM_CANOES,
ITEM_SNARES, ITEM_KNIVES, ITEM_FISHING_POLES, ITEM_ROPES, ITEM_REED_BASKETS, ITEM_CLAY_POTS, ITEM_CANOES,
// Clothing
ITEM_SKIN_HATS,
ITEM_SKIN_GLOVES,
ITEM_SKIN_PANTS,
ITEM_SKIN_TUNICS,
ITEM_MOCCASINS,
ITEM_SKIN_POUCHES,
ITEM_BACKPACKS
};
ITEM_SKIN_HATS, ITEM_SKIN_GLOVES, ITEM_SKIN_PANTS, ITEM_SKIN_TUNICS, ITEM_MOCCASINS, ITEM_SKIN_POUCHES,
ITEM_BACKPACKS};
// Initialize inventory arrays
personal_inventory.resize(ITEM_COUNT);
@@ -202,36 +179,44 @@ void reset_inventory() {
// Accessor functions for personal inventory
int get_personal_count(int item_type) {
if (item_type < 0 || item_type >= ITEM_COUNT) return 0;
if (item_type < 0 || item_type >= ITEM_COUNT)
return 0;
return personal_inventory[item_type];
}
void set_personal_count(int item_type, int count) {
if (item_type < 0 || item_type >= ITEM_COUNT) return;
if (item_type < 0 || item_type >= ITEM_COUNT)
return;
personal_inventory[item_type] = count;
}
void add_personal_count(int item_type, int amount) {
if (item_type < 0 || item_type >= ITEM_COUNT) return;
if (item_type < 0 || item_type >= ITEM_COUNT)
return;
personal_inventory[item_type] += amount;
if (personal_inventory[item_type] < 0) personal_inventory[item_type] = 0;
if (personal_inventory[item_type] < 0)
personal_inventory[item_type] = 0;
}
// Accessor functions for storage inventory
int get_storage_count(int item_type) {
if (item_type < 0 || item_type >= ITEM_COUNT) return 0;
if (item_type < 0 || item_type >= ITEM_COUNT)
return 0;
return storage_inventory[item_type];
}
void set_storage_count(int item_type, int count) {
if (item_type < 0 || item_type >= ITEM_COUNT) return;
if (item_type < 0 || item_type >= ITEM_COUNT)
return;
storage_inventory[item_type] = count;
}
void add_storage_count(int item_type, int amount) {
if (item_type < 0 || item_type >= ITEM_COUNT) return;
if (item_type < 0 || item_type >= ITEM_COUNT)
return;
storage_inventory[item_type] += amount;
if (storage_inventory[item_type] < 0) storage_inventory[item_type] = 0;
if (storage_inventory[item_type] < 0)
storage_inventory[item_type] = 0;
}
int get_default_fish_weight() {
@@ -239,8 +224,10 @@ int get_default_fish_weight() {
}
int clamp_fish_weight(int weight) {
if (weight < FISH_WEIGHT_MIN) return FISH_WEIGHT_MIN;
if (weight > FISH_WEIGHT_MAX) return FISH_WEIGHT_MAX;
if (weight < FISH_WEIGHT_MIN)
return FISH_WEIGHT_MIN;
if (weight > FISH_WEIGHT_MAX)
return FISH_WEIGHT_MAX;
return weight;
}
@@ -253,14 +240,16 @@ void add_storage_fish_weight(int weight) {
}
int pop_personal_fish_weight() {
if (personal_fish_weights.length() == 0) return get_default_fish_weight();
if (personal_fish_weights.length() == 0)
return get_default_fish_weight();
int weight = personal_fish_weights[0];
personal_fish_weights.remove_at(0);
return clamp_fish_weight(weight);
}
int pop_storage_fish_weight() {
if (storage_fish_weights.length() == 0) return get_default_fish_weight();
if (storage_fish_weights.length() == 0)
return get_default_fish_weight();
int weight = storage_fish_weights[0];
storage_fish_weights.remove_at(0);
return clamp_fish_weight(weight);
@@ -280,30 +269,37 @@ void move_fish_weights_to_personal(int amount) {
int get_smoked_fish_yield(int weight) {
int clamped = clamp_fish_weight(weight);
if (clamped <= 7) return 1;
if (clamped <= 17) return 2;
if (clamped <= 27) return 3;
if (clamped <= 7)
return 1;
if (clamped <= 17)
return 2;
if (clamped <= 27)
return 3;
return 4;
}
// Item metadata lookups
string get_item_label(int item_type) {
if (item_type < 0 || item_type >= ITEM_COUNT) return "items";
if (item_type < 0 || item_type >= ITEM_COUNT)
return "items";
return item_registry[item_type].name;
}
string get_item_label_singular(int item_type) {
if (item_type < 0 || item_type >= ITEM_COUNT) return "item";
if (item_type < 0 || item_type >= ITEM_COUNT)
return "item";
return item_registry[item_type].singular;
}
string get_item_display_name(int item_type) {
if (item_type < 0 || item_type >= ITEM_COUNT) return "Unknown";
if (item_type < 0 || item_type >= ITEM_COUNT)
return "Unknown";
return item_registry[item_type].display_name;
}
double get_item_favor_value(int item_type) {
if (item_type < 0 || item_type >= ITEM_COUNT) return 0.01;
if (item_type < 0 || item_type >= ITEM_COUNT)
return 0.01;
return item_registry[item_type].favor_value;
}
+6 -4
View File
@@ -5,7 +5,7 @@
bool learnSoundsConfigured = false;
bool docsBrowserConfigured = false;
void learn_sounds_bridge_speak(const string &in message, bool interrupt) {
void learn_sounds_bridge_speak(const string& in message, bool interrupt) {
speak_with_history(message, interrupt);
}
@@ -14,7 +14,8 @@ void learn_sounds_bridge_tick() {
}
void configure_docs_browser_if_needed() {
if (docsBrowserConfigured) return;
if (docsBrowserConfigured)
return;
docs_browser_set_speak_callback(learn_sounds_bridge_speak);
docs_browser_set_tick_callback(learn_sounds_bridge_tick);
@@ -26,13 +27,14 @@ void configure_docs_browser_if_needed() {
docsBrowserConfigured = true;
}
void add_doc_entries(string[]@ labels, string[]@ paths, int[]@ types) {
void add_doc_entries(string[] @labels, string[] @paths, int[] @types) {
configure_docs_browser_if_needed();
docs_browser_add_entries(labels, paths, types, 1);
}
void configure_learn_sounds_if_needed() {
if (learnSoundsConfigured) return;
if (learnSoundsConfigured)
return;
learn_sounds_set_speak_callback(learn_sounds_bridge_speak);
learn_sounds_set_tick_callback(learn_sounds_bridge_tick);
+28 -21
View File
@@ -7,8 +7,8 @@ void check_action_menu(int x) {
}
}
WorldSnare@ get_snare_within_range(int pos, int range) {
WorldSnare@ nearest = null;
WorldSnare @get_snare_within_range(int pos, int range) {
WorldSnare @nearest = null;
int nearest_distance = range + 1;
for (uint i = 0; i < world_snares.length(); i++) {
int dist = abs(world_snares[i].position - pos);
@@ -22,19 +22,23 @@ WorldSnare@ get_snare_within_range(int pos, int range) {
string get_fire_intensity_label(int fuel_remaining) {
int hours_remaining = fuel_remaining / 60000;
if (hours_remaining >= 8) return "Giant blaze";
if (hours_remaining >= 2) return "Small fire";
if (hours_remaining >= 8)
return "Giant blaze";
if (hours_remaining >= 2)
return "Small fire";
return "A few glowing coals";
}
string get_fire_time_estimate(int fuel_remaining) {
int approx_hours = (fuel_remaining + 30000) / 60000;
if (approx_hours <= 0) return "less than 1 hour";
if (approx_hours == 1) return "approximately 1 hour";
if (approx_hours <= 0)
return "less than 1 hour";
if (approx_hours == 1)
return "approximately 1 hour";
return "approximately " + approx_hours + " hours";
}
void check_fire_status(WorldFire@ fire) {
void check_fire_status(WorldFire @fire) {
if (fire == null) {
speak_with_history("No fire nearby.", true);
return;
@@ -44,7 +48,7 @@ void check_fire_status(WorldFire@ fire) {
speak_with_history(label + ". " + estimate + " remaining.", true);
}
void check_snare_status(WorldSnare@ snare) {
void check_snare_status(WorldSnare @snare) {
if (snare == null) {
speak_with_history("No snare nearby.", true);
return;
@@ -88,7 +92,7 @@ void try_place_snare(int x) {
}
}
void try_feed_fire_stick(WorldFire@ fire) {
void try_feed_fire_stick(WorldFire @fire) {
if (get_personal_count(ITEM_STICKS) > 0 && fire != null) {
add_personal_count(ITEM_STICKS, -1);
fire.add_fuel(300000); // 5 minutes
@@ -97,7 +101,7 @@ void try_feed_fire_stick(WorldFire@ fire) {
}
}
void try_feed_fire_vine(WorldFire@ fire) {
void try_feed_fire_vine(WorldFire @fire) {
if (get_personal_count(ITEM_VINES) > 0 && fire != null) {
add_personal_count(ITEM_VINES, -1);
fire.add_fuel(60000); // 1 minute
@@ -106,7 +110,7 @@ void try_feed_fire_vine(WorldFire@ fire) {
}
}
void try_feed_fire_log(WorldFire@ fire) {
void try_feed_fire_log(WorldFire @fire) {
if (get_personal_count(ITEM_LOGS) > 0 && fire != null) {
add_personal_count(ITEM_LOGS, -1);
fire.add_fuel(720000); // 12 minutes
@@ -136,7 +140,7 @@ void try_burn_incense() {
speak_with_history("Incense burning. " + incense_hours_remaining + " hours remaining.", true);
}
void try_feed_fire_stick_max(WorldFire@ fire) {
void try_feed_fire_stick_max(WorldFire @fire) {
if (get_personal_count(ITEM_STICKS) <= 0 || fire == null) {
speak_with_history("No sticks to feed fire.", true);
return;
@@ -151,7 +155,7 @@ void try_feed_fire_stick_max(WorldFire@ fire) {
speak_with_history("Dumped " + amount + " sticks into the fire.", true);
}
void try_feed_fire_vine_max(WorldFire@ fire) {
void try_feed_fire_vine_max(WorldFire @fire) {
if (get_personal_count(ITEM_VINES) <= 0 || fire == null) {
speak_with_history("No vines to feed fire.", true);
return;
@@ -166,7 +170,7 @@ void try_feed_fire_vine_max(WorldFire@ fire) {
speak_with_history("Dumped " + amount + " vines into the fire.", true);
}
void try_feed_fire_log_max(WorldFire@ fire) {
void try_feed_fire_log_max(WorldFire @fire) {
if (get_personal_count(ITEM_LOGS) <= 0 || fire == null) {
speak_with_history("No logs to feed fire.", true);
return;
@@ -215,10 +219,10 @@ void run_action_menu(int x) {
const int check_range = 2;
// Check if fire is nearby
WorldFire@ nearby_fire = get_fire_near(x);
WorldFire @nearby_fire = get_fire_near(x);
bool can_feed_fire = nearby_fire != null;
WorldFire@ check_fire = get_fire_within_range(x, check_range);
WorldSnare@ check_snare = get_snare_within_range(x, check_range);
WorldFire @check_fire = get_fire_within_range(x, check_range);
WorldSnare @check_snare = get_snare_within_range(x, check_range);
// Build menu options dynamically
options.insert_last("Place Snare");
@@ -261,7 +265,7 @@ void run_action_menu(int x) {
string[] filtered_options;
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -271,7 +275,8 @@ void run_action_menu(int x) {
break;
}
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
bool filter_changed =
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
if (filter_changed) {
if (filtered_options.length() == 0) {
if (filter_text.length() > 0) {
@@ -288,7 +293,8 @@ void run_action_menu(int x) {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection++;
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
speak_with_history(filtered_options[selection], true);
}
}
@@ -297,7 +303,8 @@ void run_action_menu(int x) {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = int(filtered_options.length()) - 1;
if (selection < 0)
selection = int(filtered_options.length()) - 1;
speak_with_history(filtered_options[selection], true);
}
}
+23 -14
View File
@@ -2,12 +2,14 @@
// Functions for sacrificing items at the altar
string format_altar_favor(double value) {
if (value < 0) value = 0;
if (value < 0)
value = 0;
return "" + int(value);
}
void check_altar_menu(int player_x) {
if (!key_pressed(KEY_S)) return;
if (!key_pressed(KEY_S))
return;
// Must be in base
if (player_x > BASE_END) {
@@ -40,15 +42,16 @@ void sacrifice_item(int item_type) {
if (personal_small_game_types.length() > 0) {
personal_small_game_types.remove_at(0);
}
}
else {
} else {
add_personal_count(item_type, -1);
}
cleanup_equipment_after_inventory_change();
double favor_gain = get_item_favor_value(item_type);
favor += favor_gain;
speak_with_history("Sacrificed 1 " + get_item_label_singular(item_type) + ". Favor +" + format_altar_favor(favor_gain) + ". Total " + format_altar_favor(favor) + ".", true);
speak_with_history("Sacrificed 1 " + get_item_label_singular(item_type) + ". Favor +" +
format_altar_favor(favor_gain) + ". Total " + format_altar_favor(favor) + ".",
true);
}
void sacrifice_item_max(int item_type) {
@@ -67,8 +70,7 @@ void sacrifice_item_max(int item_type) {
if (item_type == ITEM_SMALL_GAME) {
set_personal_count(ITEM_SMALL_GAME, 0);
personal_small_game_types.resize(0);
}
else {
} else {
set_personal_count(item_type, 0);
}
@@ -76,7 +78,9 @@ void sacrifice_item_max(int item_type) {
double total_favor = favor_per_item * available;
favor += total_favor;
speak_with_history("Sacrificed " + available + " " + get_item_label(item_type) + ". Favor +" + format_altar_favor(total_favor) + ". Total " + format_altar_favor(favor) + ".", true);
speak_with_history("Sacrificed " + available + " " + get_item_label(item_type) + ". Favor +" +
format_altar_favor(total_favor) + ". Total " + format_altar_favor(favor) + ".",
true);
}
void run_altar_menu() {
@@ -91,7 +95,7 @@ void run_altar_menu() {
string[] filtered_options;
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -101,7 +105,8 @@ void run_altar_menu() {
break;
}
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
bool filter_changed =
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
if (filter_changed) {
if (filtered_options.length() == 0) {
if (filter_text.length() > 0) {
@@ -118,7 +123,8 @@ void run_altar_menu() {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection++;
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
speak_with_history(filtered_options[selection], true);
}
}
@@ -127,7 +133,8 @@ void run_altar_menu() {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = int(filtered_options.length()) - 1;
if (selection < 0)
selection = int(filtered_options.length()) - 1;
speak_with_history(filtered_options[selection], true);
}
}
@@ -138,7 +145,8 @@ void run_altar_menu() {
sacrifice_item(item_types[filtered_indices[selection]]);
build_personal_inventory_options(options, item_types);
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
if (filtered_options.length() > 0) {
speak_with_history(filtered_options[selection], true);
} else if (filter_text.length() > 0) {
@@ -153,7 +161,8 @@ void run_altar_menu() {
sacrifice_item_max(item_types[filtered_indices[selection]]);
build_personal_inventory_options(options, item_types);
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
if (filtered_options.length() > 0) {
speak_with_history(filtered_options[selection], true);
} else if (filter_text.length() > 0) {
+18 -9
View File
@@ -23,18 +23,24 @@ void run_base_info_menu() {
int smoked_fish_in_storage = get_storage_count(ITEM_SMOKED_FISH);
int basket_food_in_storage = get_storage_count(ITEM_BASKET_FOOD);
int total_food = meat_in_storage + smoked_fish_in_storage + basket_food_in_storage;
options.insert_last("Food in storage " + meat_in_storage + " meat, " + smoked_fish_in_storage + " smoked fish, " + basket_food_in_storage + " baskets of fruits and nuts. Total " + total_food + ". Daily use " + daily_food);
options.insert_last("Food in storage " + meat_in_storage + " meat, " + smoked_fish_in_storage +
" smoked fish, " + basket_food_in_storage + " baskets of fruits and nuts. Total " +
total_food + ". Daily use " + daily_food);
} else {
options.insert_last("Storage not built");
}
options.insert_last(get_base_fire_status());
if (world_altars.length() > 0) options.insert_last("Altar built");
else options.insert_last("Altar not built");
if (world_altars.length() > 0)
options.insert_last("Altar built");
else
options.insert_last("Altar not built");
if (get_herb_garden_at_base() != null) options.insert_last("Herb garden built");
else options.insert_last("Herb garden not built");
if (get_herb_garden_at_base() != null)
options.insert_last("Herb garden built");
else
options.insert_last("Herb garden not built");
if (world_pastures.length() > 0) {
options.insert_last("Pasture built. Livestock " + livestock_count + " of " + MAX_LIVESTOCK);
@@ -57,7 +63,7 @@ void run_base_info_menu() {
speak_with_history("Base info. " + filtered_options[selection], true);
}
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -67,7 +73,8 @@ void run_base_info_menu() {
break;
}
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
bool filter_changed =
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
if (filter_changed) {
if (filtered_options.length() == 0) {
if (filter_text.length() > 0) {
@@ -84,7 +91,8 @@ void run_base_info_menu() {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection++;
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
speak_with_history(filtered_options[selection], true);
}
}
@@ -93,7 +101,8 @@ void run_base_info_menu() {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = int(filtered_options.length()) - 1;
if (selection < 0)
selection = int(filtered_options.length()) - 1;
speak_with_history(filtered_options[selection], true);
}
}
+108 -17
View File
@@ -1,25 +1,88 @@
// Character info display
// Functions for displaying character stats and equipment
bool run_pet_abandon_confirm_menu() {
if (!petActive) {
speak_with_history("No pet.", true);
return false;
}
string[] options;
options.insert_last("No");
options.insert_last("Yes");
int selection = 0;
speak_with_history("Really abandon your pet? " + options[selection], true);
while (true) {
wait(5);
if (menu_background_tick()) {
return false;
}
if (key_pressed(KEY_ESCAPE)) {
speak_with_history("Canceled.", true);
return false;
}
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= int(options.length()))
selection = 0;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0)
selection = int(options.length()) - 1;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
play_menu_select_sound();
if (selection == 1) {
return abandon_pet();
}
speak_with_history("Canceled.", true);
return false;
}
}
return false;
}
void run_character_info_menu() {
string[] equipped_clothing;
string[] missing_slots;
if (equipped_head == EQUIP_HAT) equipped_clothing.insert_last("Skin Hat");
else missing_slots.insert_last("head");
if (equipped_torso == EQUIP_TUNIC) equipped_clothing.insert_last("Skin Tunic");
else missing_slots.insert_last("torso");
if (equipped_arms == EQUIP_POUCH) equipped_clothing.insert_last("Skin Pouch");
else if (equipped_arms == EQUIP_BACKPACK) equipped_clothing.insert_last("Backpack");
else missing_slots.insert_last("arms");
if (equipped_hands == EQUIP_GLOVES) equipped_clothing.insert_last("Skin Gloves");
else missing_slots.insert_last("hands");
if (equipped_legs == EQUIP_PANTS) equipped_clothing.insert_last("Skin Pants");
else missing_slots.insert_last("legs");
if (equipped_feet == EQUIP_MOCCASINS) equipped_clothing.insert_last("Moccasins");
else missing_slots.insert_last("feet");
if (equipped_head == EQUIP_HAT)
equipped_clothing.insert_last("Skin Hat");
else
missing_slots.insert_last("head");
if (equipped_torso == EQUIP_TUNIC)
equipped_clothing.insert_last("Skin Tunic");
else
missing_slots.insert_last("torso");
if (equipped_arms == EQUIP_POUCH)
equipped_clothing.insert_last("Skin Pouch");
else if (equipped_arms == EQUIP_BACKPACK)
equipped_clothing.insert_last("Backpack");
else
missing_slots.insert_last("arms");
if (equipped_hands == EQUIP_GLOVES)
equipped_clothing.insert_last("Skin Gloves");
else
missing_slots.insert_last("hands");
if (equipped_legs == EQUIP_PANTS)
equipped_clothing.insert_last("Skin Pants");
else
missing_slots.insert_last("legs");
if (equipped_feet == EQUIP_MOCCASINS)
equipped_clothing.insert_last("Moccasins");
else
missing_slots.insert_last("feet");
string[] options;
int petOptionIndex = -1;
if (player_name != "") {
string sex_label = (player_sex == SEX_FEMALE) ? "Female" : "Male";
options.insert_last("Name " + player_name + ". Sex " + sex_label + ".");
@@ -46,6 +109,7 @@ void run_character_info_menu() {
petInfo += " Knocked out. " + petKnockoutHoursRemaining + " " + hourLabel + " remaining.";
}
options.insert_last(petInfo);
petOptionIndex = options.length() - 1;
} else {
options.insert_last("Pet none.");
}
@@ -61,7 +125,7 @@ void run_character_info_menu() {
speak_with_history("Character info. " + filtered_options[selection], true);
}
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -71,7 +135,8 @@ void run_character_info_menu() {
break;
}
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
bool filter_changed =
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
if (filter_changed) {
if (filtered_options.length() == 0) {
if (filter_text.length() > 0) {
@@ -88,7 +153,8 @@ void run_character_info_menu() {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection++;
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
speak_with_history(filtered_options[selection], true);
}
}
@@ -97,10 +163,35 @@ void run_character_info_menu() {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = int(filtered_options.length()) - 1;
if (selection < 0)
selection = int(filtered_options.length()) - 1;
speak_with_history(filtered_options[selection], true);
}
}
if (key_pressed(KEY_RETURN)) {
if (filtered_options.length() == 0)
continue;
int optionIndex = filtered_indices[selection];
if (optionIndex == petOptionIndex && petActive) {
if (is_pet_knocked_out()) {
speak_with_history(
"Your " + get_pet_display_name() + " is unconscious. You can't abandon it right now.", true);
continue;
}
play_menu_select_sound();
if (run_pet_abandon_confirm_menu()) {
return;
}
if (selection >= int(filtered_options.length()))
selection = int(filtered_options.length()) - 1;
if (selection >= 0 && selection < int(filtered_options.length())) {
speak_with_history(filtered_options[selection], true);
}
}
}
}
}
+15 -11
View File
@@ -6,11 +6,10 @@ bool has_any_equipment() {
// Check unruned items
if (get_personal_count(ITEM_SPEARS) > 0 || get_personal_count(ITEM_AXES) > 0 ||
get_personal_count(ITEM_SLINGS) > 0 || get_personal_count(ITEM_BOWS) > 0 ||
get_personal_count(ITEM_FISHING_POLES) > 0 ||
get_personal_count(ITEM_SKIN_HATS) > 0 || get_personal_count(ITEM_SKIN_GLOVES) > 0 ||
get_personal_count(ITEM_SKIN_PANTS) > 0 || get_personal_count(ITEM_SKIN_TUNICS) > 0 ||
get_personal_count(ITEM_MOCCASINS) > 0 || get_personal_count(ITEM_SKIN_POUCHES) > 0 ||
get_personal_count(ITEM_BACKPACKS) > 0) {
get_personal_count(ITEM_FISHING_POLES) > 0 || get_personal_count(ITEM_SKIN_HATS) > 0 ||
get_personal_count(ITEM_SKIN_GLOVES) > 0 || get_personal_count(ITEM_SKIN_PANTS) > 0 ||
get_personal_count(ITEM_SKIN_TUNICS) > 0 || get_personal_count(ITEM_MOCCASINS) > 0 ||
get_personal_count(ITEM_SKIN_POUCHES) > 0 || get_personal_count(ITEM_BACKPACKS) > 0) {
return true;
}
@@ -50,7 +49,8 @@ string get_full_equipment_name(int equip_type, int rune_type) {
// Check if an item with specific rune is equipped
bool is_runed_item_equipped(int equip_type, int rune_type) {
if (!equipment_is_equipped(equip_type)) return false;
if (!equipment_is_equipped(equip_type))
return false;
return get_equipped_rune_for_slot(equip_type) == rune_type;
}
@@ -145,7 +145,8 @@ void run_equipment_menu() {
for (uint j = 0; j < all_rune_types.length(); j++) {
int rune_type = all_rune_types[j];
int count = get_runed_item_count(equip_type, rune_type);
if (count <= 0) continue;
if (count <= 0)
continue;
string name = get_full_equipment_name(equip_type, rune_type);
string status = is_runed_item_equipped(equip_type, rune_type) ? " (equipped)" : "";
options.insert_last(name + status);
@@ -158,7 +159,7 @@ void run_equipment_menu() {
string[] filtered_options;
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -168,7 +169,8 @@ void run_equipment_menu() {
break;
}
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
bool filter_changed =
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
if (filter_changed) {
if (filtered_options.length() == 0) {
if (filter_text.length() > 0) {
@@ -185,7 +187,8 @@ void run_equipment_menu() {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection++;
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
speak_with_history(filtered_options[selection], true);
}
}
@@ -194,7 +197,8 @@ void run_equipment_menu() {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = int(filtered_options.length()) - 1;
if (selection < 0)
selection = int(filtered_options.length()) - 1;
speak_with_history(filtered_options[selection], true);
}
}
+29 -16
View File
@@ -1,7 +1,7 @@
// Personal inventory menu system
// Functions for displaying and managing personal inventory
void build_personal_inventory_options(string[]@ options, int[]@ item_types) {
void build_personal_inventory_options(string[] @options, int[] @item_types) {
options.resize(0);
item_types.resize(0);
@@ -23,7 +23,8 @@ void build_personal_inventory_options(string[]@ options, int[]@ item_types) {
for (uint j = 0; j < rune_types.length(); j++) {
int rune_type = rune_types[j];
int count = get_runed_item_count(equip_type, rune_type);
if (count <= 0) continue;
if (count <= 0)
continue;
string name = get_runed_item_display_name(equip_type, rune_type);
options.insert_last(name + ": " + count);
item_types.insert_last(encode_runed_item_type(equip_type, rune_type));
@@ -40,7 +41,8 @@ void show_inventory() {
int item_type = inventory_display_order[i];
int count = get_personal_count(item_type);
if (count > 0) {
if (!first) info += ", ";
if (!first)
info += ", ";
info += count + " " + get_item_label(item_type);
first = false;
}
@@ -60,8 +62,10 @@ void show_inventory() {
for (uint j = 0; j < rune_types.length(); j++) {
int rune_type = rune_types[j];
int count = get_runed_item_count(equip_type, rune_type);
if (count <= 0) continue;
if (runed_info.length() > 0) runed_info += ", ";
if (count <= 0)
continue;
if (runed_info.length() > 0)
runed_info += ", ";
runed_info += count + " " + get_runed_item_display_name(equip_type, rune_type);
}
}
@@ -79,7 +83,7 @@ void run_inventory_root_menu() {
int selection = 0;
string[] options = {"Personal inventory", "Base storage"};
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -92,21 +96,25 @@ void run_inventory_root_menu() {
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= options.length()) selection = 0;
if (selection >= options.length())
selection = 0;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = options.length() - 1;
if (selection < 0)
selection = options.length() - 1;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
play_menu_select_sound();
if (selection == 0) run_inventory_menu(true);
else run_storage_menu();
if (selection == 0)
run_inventory_menu(true);
else
run_storage_menu();
break;
}
}
@@ -124,7 +132,7 @@ void run_inventory_menu(bool allow_deposit) {
string[] filtered_options;
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -134,7 +142,8 @@ void run_inventory_menu(bool allow_deposit) {
break;
}
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
bool filter_changed =
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
if (filter_changed) {
if (filtered_options.length() == 0) {
if (filter_text.length() > 0) {
@@ -151,7 +160,8 @@ void run_inventory_menu(bool allow_deposit) {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection++;
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
speak_with_history(filtered_options[selection], true);
}
}
@@ -160,7 +170,8 @@ void run_inventory_menu(bool allow_deposit) {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = int(filtered_options.length()) - 1;
if (selection < 0)
selection = int(filtered_options.length()) - 1;
speak_with_history(filtered_options[selection], true);
}
}
@@ -181,7 +192,8 @@ void run_inventory_menu(bool allow_deposit) {
deposit_item(item_types[filtered_indices[selection]]);
build_personal_inventory_options(options, item_types);
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
if (filtered_options.length() > 0) {
speak_with_history(filtered_options[selection], true);
} else if (filter_text.length() > 0) {
@@ -196,7 +208,8 @@ void run_inventory_menu(bool allow_deposit) {
deposit_item_max(item_types[filtered_indices[selection]]);
build_personal_inventory_options(options, item_types);
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
if (filtered_options.length() > 0) {
speak_with_history(filtered_options[selection], true);
} else if (filter_text.length() > 0) {
+15 -9
View File
@@ -28,7 +28,7 @@ bool menu_background_tick() {
update_notifications();
// Fire damage check (only if not jumping)
WorldFire@ fire_on_tile = get_fire_at(x);
WorldFire @fire_on_tile = get_fire_at(x);
if (fire_on_tile != null && !jumping && fire_damage_timer.elapsed > 1000) {
player_health--;
fire_damage_timer.restart();
@@ -37,7 +37,7 @@ bool menu_background_tick() {
// Healing in base area
if (x <= BASE_END && player_health < max_health) {
WorldHerbGarden@ herb_garden = get_herb_garden_at_base();
WorldHerbGarden @herb_garden = get_herb_garden_at_base();
int heal_interval = (herb_garden != null) ? 30000 : 150000; // 30 seconds with garden, 2.5 minutes without
if (healing_timer.elapsed > heal_interval) {
@@ -62,18 +62,21 @@ bool menu_background_tick() {
void play_menu_move_sound() {
string soundFile = "sounds/menu/menu_move.ogg";
if (!file_exists(soundFile)) return;
if (!audio_asset_exists(soundFile))
return;
p.play_stationary(soundFile, false);
}
void play_menu_select_sound() {
string soundFile = "sounds/menu/menu_select.ogg";
if (!file_exists(soundFile)) return;
if (!audio_asset_exists(soundFile))
return;
p.play_stationary(soundFile, false);
}
string join_string_list(const string[]@ items) {
if (@items == null || items.length() == 0) return "";
string join_string_list(const string[] @items) {
if (@items == null || items.length() == 0)
return "";
string result = items[0];
for (uint i = 1; i < items.length(); i++) {
result += ", " + items[i];
@@ -100,7 +103,8 @@ string get_base_fire_status() {
}
}
}
if (total == 0) return "No fires in base";
if (total == 0)
return "No fires in base";
return "Fires in base: " + burning + " burning, " + total + " total";
}
@@ -108,10 +112,12 @@ string get_menu_filter_letter() {
return menu_get_filter_letter();
}
void apply_menu_filter(const string &in filter_text, const string[]@ options, int[]@ filtered_indices, string[]@ filtered_options) {
void apply_menu_filter(const string& in filter_text, const string[] @options, int[] @filtered_indices,
string[] @filtered_options) {
menu_apply_prefix_filter(filter_text, options, filtered_indices, filtered_options);
}
bool update_menu_filter_state(string &inout filter_text, const string[]@ options, int[]@ filtered_indices, string[]@ filtered_options, int &inout selection) {
bool update_menu_filter_state(string& inout filter_text, const string[] @options, int[] @filtered_indices,
string[] @filtered_options, int& inout selection) {
return menu_update_prefix_filter(filter_text, options, filtered_indices, filtered_options, selection);
}
+22 -12
View File
@@ -34,8 +34,10 @@ void move_fish_to_personal(int amount) {
int prompt_transfer_amount(const string prompt, int max_amount) {
string input = ui_input_box("Inventory", prompt + " (max " + max_amount + ")", "");
int amount = parse_int(input);
if (amount <= 0) return 0;
if (amount > max_amount) amount = max_amount;
if (amount <= 0)
return 0;
if (amount > max_amount)
amount = max_amount;
return amount;
}
@@ -70,7 +72,8 @@ void deposit_item(int item_type) {
}
int max_transfer = (available < capacity) ? available : capacity;
int amount = prompt_transfer_amount("Deposit how many?", max_transfer);
if (amount <= 0) return;
if (amount <= 0)
return;
// Transfer the items
add_personal_count(item_type, -amount);
@@ -177,7 +180,8 @@ void withdraw_item(int item_type) {
}
int max_transfer = (available < capacity) ? available : capacity;
int amount = prompt_transfer_amount("Withdraw how many?", max_transfer);
if (amount <= 0) return;
if (amount <= 0)
return;
// Transfer the items
add_storage_count(item_type, -amount);
@@ -256,7 +260,7 @@ void withdraw_item_max(int item_type) {
speak_with_history("Withdrew " + amount + " " + get_item_label(item_type) + ".", true);
}
void build_storage_inventory_options(string[]@ options, int[]@ item_types) {
void build_storage_inventory_options(string[] @options, int[] @item_types) {
options.resize(0);
item_types.resize(0);
@@ -278,7 +282,8 @@ void build_storage_inventory_options(string[]@ options, int[]@ item_types) {
for (uint j = 0; j < rune_types.length(); j++) {
int rune_type = rune_types[j];
int count = get_stored_runed_item_count(equip_type, rune_type);
if (count <= 0) continue;
if (count <= 0)
continue;
string name = get_runed_item_display_name(equip_type, rune_type);
options.insert_last(name + ": " + count);
item_types.insert_last(encode_runed_item_type(equip_type, rune_type));
@@ -303,7 +308,7 @@ void run_storage_menu() {
string[] filtered_options;
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -313,7 +318,8 @@ void run_storage_menu() {
break;
}
bool filter_changed = update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
bool filter_changed =
update_menu_filter_state(filter_text, options, filtered_indices, filtered_options, selection);
if (filter_changed) {
if (filtered_options.length() == 0) {
if (filter_text.length() > 0) {
@@ -330,7 +336,8 @@ void run_storage_menu() {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection++;
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
speak_with_history(filtered_options[selection], true);
}
}
@@ -339,7 +346,8 @@ void run_storage_menu() {
if (filtered_options.length() > 0) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = int(filtered_options.length()) - 1;
if (selection < 0)
selection = int(filtered_options.length()) - 1;
speak_with_history(filtered_options[selection], true);
}
}
@@ -350,7 +358,8 @@ void run_storage_menu() {
withdraw_item(item_types[filtered_indices[selection]]);
build_storage_inventory_options(options, item_types);
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
if (filtered_options.length() > 0) {
speak_with_history(filtered_options[selection], true);
} else if (filter_text.length() > 0) {
@@ -365,7 +374,8 @@ void run_storage_menu() {
withdraw_item_max(item_types[filtered_indices[selection]]);
build_storage_inventory_options(options, item_types);
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
if (selection >= int(filtered_options.length())) selection = 0;
if (selection >= int(filtered_options.length()))
selection = 0;
if (filtered_options.length() > 0) {
speak_with_history(filtered_options[selection], true);
} else if (filter_text.length() > 0) {
+3 -2
View File
@@ -6,12 +6,13 @@ const string NOTIFICATION_SOUND_PATH = "sounds/notify";
bool notificationsCompatConfigured = false;
void notify_compat_speak(const string &in message, bool interrupt) {
void notify_compat_speak(const string& in message, bool interrupt) {
speak_with_history(message, interrupt);
}
void configure_notification_compat_if_needed() {
if (notificationsCompatConfigured) return;
if (notificationsCompatConfigured)
return;
notifications_set_max_history(NOTIFICATION_HISTORY_LIMIT);
notifications_set_delay_ms(NOTIFICATION_DELAY_MS);
+268 -154
View File
@@ -43,7 +43,8 @@ string petLeavingName = "";
string[] petSoundPaths;
bool petSoundsInitialized = false;
funcdef bool PetAdventureFindTargetCallback(int originPos, int referencePos, int &out targetPos, string &out targetLabel, int &out targetKind);
funcdef bool PetAdventureFindTargetCallback(int originPos, int referencePos, int& out targetPos,
string& out targetLabel, int& out targetKind);
funcdef bool PetAdventureDamageCallback(int targetKind, int targetPos, int damage);
bool petAdventureMode = false;
@@ -51,14 +52,14 @@ int petAdventurePlayerPos = -1;
bool petAdventurePreOut = false;
int petAdventurePrePosition = 0;
bool petAdventurePrePositionValid = false;
PetAdventureFindTargetCallback@ petAdventureFindTarget = null;
PetAdventureDamageCallback@ petAdventureDamageTarget = null;
PetAdventureFindTargetCallback @petAdventureFindTarget = null;
PetAdventureDamageCallback @petAdventureDamageTarget = null;
string normalize_pet_path(const string&in path) {
string normalize_pet_path(const string& in path) {
return path.replace("\\", "/", true);
}
string collapse_pet_spaces(const string&in text) {
string collapse_pet_spaces(const string& in text) {
string result = text;
while (result.find_first(" ") > -1) {
result = result.replace(" ", " ", true);
@@ -66,7 +67,7 @@ string collapse_pet_spaces(const string&in text) {
return result;
}
string normalize_pet_name_text(const string&in raw) {
string normalize_pet_name_text(const string& in raw) {
string name = raw;
name = name.replace("_", " ", true);
name = name.replace("-", " ", true);
@@ -75,15 +76,15 @@ string normalize_pet_name_text(const string&in raw) {
return name;
}
void gather_pet_sound_files(const string&in basePath, string[]@ outFiles) {
string[]@ files = find_files(basePath + "/*.ogg");
void gather_pet_sound_files(const string& in basePath, string[] @outFiles) {
string[] @files = find_files(basePath + "/*.ogg");
if (@files !is null) {
for (uint i = 0; i < files.length(); i++) {
outFiles.insert_last(basePath + "/" + files[i]);
}
}
string[]@ folders = find_directories(basePath + "/*");
string[] @folders = find_directories(basePath + "/*");
if (@folders !is null) {
for (uint i = 0; i < folders.length(); i++) {
gather_pet_sound_files(basePath + "/" + folders[i], outFiles);
@@ -91,22 +92,24 @@ void gather_pet_sound_files(const string&in basePath, string[]@ outFiles) {
}
}
bool sort_pet_sound_paths(const string &in a, const string &in b) {
bool sort_pet_sound_paths(const string& in a, const string& in b) {
return a.lower() < b.lower();
}
void init_pet_sounds() {
if (petSoundsInitialized) return;
if (petSoundsInitialized)
return;
petSoundsInitialized = true;
petSoundPaths.resize(0);
if (!directory_exists("sounds/pets")) return;
if (!directory_exists("sounds/pets"))
return;
gather_pet_sound_files("sounds/pets", petSoundPaths);
if (petSoundPaths.length() > 1) {
petSoundPaths.sort(sort_pet_sound_paths);
}
}
string get_pet_name_from_sound_path(const string&in soundPath) {
string get_pet_name_from_sound_path(const string& in soundPath) {
string normalizedPath = normalize_pet_path(soundPath);
int slashPos = normalizedPath.find_last_of("/");
string name = (slashPos >= 0) ? normalizedPath.substr(slashPos + 1) : normalizedPath;
@@ -119,13 +122,15 @@ string get_pet_name_from_sound_path(const string&in soundPath) {
name = collapse_pet_spaces(name);
name = name.lower();
name.trim_whitespace_this();
if (name.length() == 0) return "Pet";
if (name.length() == 0)
return "Pet";
string first = name.substr(0, 1).upper();
if (name.length() == 1) return first;
if (name.length() == 1)
return first;
return first + name.substr(1);
}
string get_pet_sound_for_name(const string&in petName) {
string get_pet_sound_for_name(const string& in petName) {
init_pet_sounds();
string target = petName.lower();
for (uint i = 0; i < petSoundPaths.length(); i++) {
@@ -144,17 +149,13 @@ string get_pet_sound_for_name(const string&in petName) {
}
int get_pet_food_personal_total() {
return get_personal_count(ITEM_MEAT)
+ get_personal_count(ITEM_SMOKED_FISH)
+ get_personal_count(ITEM_FISH)
+ get_personal_count(ITEM_BASKET_FOOD);
return get_personal_count(ITEM_MEAT) + get_personal_count(ITEM_SMOKED_FISH) + get_personal_count(ITEM_FISH) +
get_personal_count(ITEM_BASKET_FOOD);
}
int get_pet_food_storage_total() {
return get_storage_count(ITEM_MEAT)
+ get_storage_count(ITEM_SMOKED_FISH)
+ get_storage_count(ITEM_FISH)
+ get_storage_count(ITEM_BASKET_FOOD);
return get_storage_count(ITEM_MEAT) + get_storage_count(ITEM_SMOKED_FISH) + get_storage_count(ITEM_FISH) +
get_storage_count(ITEM_BASKET_FOOD);
}
bool has_pet_food_available() {
@@ -199,9 +200,11 @@ bool consume_pet_food() {
return false;
}
void queue_pet_event(const string&in message, int soundPos = -1, bool playSound = true) {
if (!petActive) return;
if (message.length() == 0) return;
void queue_pet_event(const string& in message, int soundPos = -1, bool playSound = true) {
if (!petActive)
return;
if (message.length() == 0)
return;
petEventMessages.insert_last(message);
if (playSound) {
petEventSounds.insert_last(petSoundPath);
@@ -213,12 +216,14 @@ void queue_pet_event(const string&in message, int soundPos = -1, bool playSound
string get_pet_display_name() {
string name = normalize_pet_name_text(petType);
if (name == "") return "pet";
if (name == "")
return "pet";
return name;
}
int get_pet_listener_pos() {
if (petAdventurePlayerPos >= 0) return petAdventurePlayerPos;
if (petAdventurePlayerPos >= 0)
return petAdventurePlayerPos;
return x;
}
@@ -232,7 +237,8 @@ string get_health_report() {
}
int get_pet_search_origin() {
if (petOut && petPositionValid) return petPosition;
if (petOut && petPositionValid)
return petPosition;
return get_pet_listener_pos();
}
@@ -241,14 +247,16 @@ bool is_hawk_pet() {
}
void play_pet_travel_step_sound(int stepPos) {
if (stepPos < 0 || stepPos >= MAP_SIZE) return;
if (stepPos < 0 || stepPos >= MAP_SIZE)
return;
int listenerPos = get_pet_listener_pos();
if (abs(stepPos - listenerPos) > CREATURE_DEFAULT_FOOTSTEP_DISTANCE) return;
if (abs(stepPos - listenerPos) > CREATURE_DEFAULT_FOOTSTEP_DISTANCE)
return;
if (is_hawk_pet()) {
string flySoundPath = "sounds/terrain/fly.ogg";
if (file_exists(flySoundPath)) {
if (audio_asset_exists(flySoundPath)) {
play_1d_with_volume_step(flySoundPath, listenerPos, stepPos, false, CREATURE_DEFAULT_VOLUME_STEP);
return;
}
@@ -264,13 +272,15 @@ void update_pet_travel_position(int currentPos) {
petPositionValid = true;
previousPos = petPosition;
}
if (currentPos == previousPos) return;
if (currentPos == previousPos)
return;
int stepDir = (currentPos > previousPos) ? 1 : -1;
int stepPos = previousPos + stepDir;
while (true) {
play_pet_travel_step_sound(stepPos);
if (stepPos == currentPos) break;
if (stepPos == currentPos)
break;
stepPos += stepDir;
}
petPosition = currentPos;
@@ -280,7 +290,8 @@ bool is_pet_knocked_out() {
return petKnockoutHoursRemaining > 0 || petHealth <= 0;
}
void begin_pet_adventure(PetAdventureFindTargetCallback@ findTarget, PetAdventureDamageCallback@ damageTarget, int playerPos) {
void begin_pet_adventure(PetAdventureFindTargetCallback @findTarget, PetAdventureDamageCallback @damageTarget,
int playerPos) {
petAdventureMode = true;
petAdventurePlayerPos = playerPos;
petAdventurePreOut = petOut;
@@ -320,7 +331,8 @@ void end_pet_adventure() {
}
void queue_pet_return_event() {
if (!petActive) return;
if (!petActive)
return;
queue_pet_event("A " + get_pet_display_name() + " returns to you.");
}
@@ -329,12 +341,14 @@ bool is_pet_at_player_position() {
}
bool is_pet_within_follow_distance() {
if (!petPositionValid) return false;
if (!petPositionValid)
return false;
return abs(petPosition - get_pet_listener_pos()) <= PET_FOLLOW_MAX_DISTANCE;
}
bool is_pet_within_follow_comfort_distance() {
if (!petPositionValid) return false;
if (!petPositionValid)
return false;
return abs(petPosition - get_pet_listener_pos()) <= PET_FOLLOW_COMFORT_DISTANCE;
}
@@ -347,7 +361,8 @@ void complete_pet_return() {
}
void knock_out_pet() {
if (!petActive) return;
if (!petActive)
return;
petHealth = 0;
petKnockoutHoursRemaining = PET_KNOCKOUT_COOLDOWN_HOURS;
petOut = false;
@@ -377,9 +392,10 @@ void update_pet_events() {
string soundPath = petEventSounds[0];
int soundPos = petEventPositions[0];
if (soundPath != "" && file_exists(soundPath)) {
if (soundPath != "" && audio_asset_exists(soundPath)) {
if (soundPos >= 0) {
petEventSoundHandle = play_1d_with_volume_step(soundPath, get_pet_listener_pos(), soundPos, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
petEventSoundHandle = play_1d_with_volume_step(soundPath, get_pet_listener_pos(), soundPos, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
} else {
petEventSoundHandle = p.play_stationary(soundPath, false);
}
@@ -432,10 +448,12 @@ void reset_pet_state() {
}
void pet_leave() {
if (!petActive) return;
if (!petActive)
return;
string oldPet = normalize_pet_name_text(petType);
if (oldPet == "") oldPet = "pet";
if (oldPet == "")
oldPet = "pet";
speak_with_history(oldPet + " leaves.", true);
if (!petOut) {
@@ -449,6 +467,28 @@ void pet_leave() {
stop_pet_travel();
}
bool abandon_pet() {
if (!petActive)
return false;
if (is_pet_knocked_out()) {
speak_with_history("Your " + get_pet_display_name() + " is unconscious. You can't abandon it right now.", true);
return false;
}
// Force the pet out first so leaving uses travel-out behavior instead of instant reset.
if (!petOut) {
petOut = true;
petRecallRequested = false;
petPosition = get_pet_listener_pos();
petPositionValid = true;
}
petLoyalty = 0;
pet_leave();
return true;
}
void start_pet_travel_leave() {
stop_pet_travel();
petTravelActive = true;
@@ -469,24 +509,22 @@ void start_pet_travel_leave() {
petTravelDurationMs = get_pet_travel_duration_ms(petTravelStartPos, petTravelTargetPos, true);
petTravelTimer.restart();
if (petSoundPath != "" && file_exists(petSoundPath)) {
petTravelSoundHandle = play_1d_with_volume_step(
petSoundPath,
get_pet_listener_pos(),
petTravelStartPos,
true,
PLAYER_WEAPON_SOUND_VOLUME_STEP
);
if (petSoundPath != "" && audio_asset_exists(petSoundPath)) {
petTravelSoundHandle = play_1d_with_volume_step(petSoundPath, get_pet_listener_pos(), petTravelStartPos, true,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
}
}
void clamp_pet_loyalty() {
if (petLoyalty < 0) petLoyalty = 0;
if (petLoyalty > PET_LOYALTY_MAX) petLoyalty = PET_LOYALTY_MAX;
if (petLoyalty < 0)
petLoyalty = 0;
if (petLoyalty > PET_LOYALTY_MAX)
petLoyalty = PET_LOYALTY_MAX;
}
void adjust_pet_loyalty(int delta) {
if (!petActive) return;
if (!petActive)
return;
petLoyalty += delta;
clamp_pet_loyalty();
if (petLoyalty <= 0) {
@@ -495,10 +533,12 @@ void adjust_pet_loyalty(int delta) {
}
void check_pet_call_key() {
if (!key_pressed(KEY_SPACE)) return;
if (!key_pressed(KEY_SPACE))
return;
if (petLeaving) {
string name = petLeavingName;
if (name == "") name = "pet";
if (name == "")
name = "pet";
speak_with_history("Your " + name + " is leaving.", true);
return;
}
@@ -527,19 +567,20 @@ void check_pet_call_key() {
return;
}
adjust_pet_loyalty(-PET_LOYALTY_CALLOUT_COST);
if (!petActive) return;
if (!petActive)
return;
petOut = true;
petRecallRequested = false;
petPosition = get_pet_listener_pos();
petPositionValid = true;
if (file_exists("sounds/actions/call_pet.ogg")) {
if (audio_asset_exists("sounds/actions/call_pet.ogg")) {
/* But I can feel it, black water washes over me.
As it soothes I call to you with my control. */
p.play_stationary("sounds/actions/call_pet.ogg", false);
}
}
void adopt_pet(const string&in soundPath) {
void adopt_pet(const string& in soundPath) {
petActive = true;
petSoundPath = soundPath;
petType = get_pet_name_from_sound_path(soundPath);
@@ -575,15 +616,17 @@ int get_pet_travel_duration_ms(int startPos, int targetPos, bool chargeTravel =
int speedPerTile = walk_speed;
if (chargeTravel) {
speedPerTile = int(float(walk_speed) / PET_CHARGE_SPEED_MULTIPLIER);
if (speedPerTile < 1) speedPerTile = 1;
if (speedPerTile < 1)
speedPerTile = 1;
}
int duration = distance * speedPerTile;
if (duration < PET_TRAVEL_MIN_MS) duration = PET_TRAVEL_MIN_MS;
if (duration < PET_TRAVEL_MIN_MS)
duration = PET_TRAVEL_MIN_MS;
return duration;
}
void start_pet_travel_attack(int targetPos, const string&in targetLabel, int targetKind) {
void start_pet_travel_attack(int targetPos, const string& in targetLabel, int targetKind) {
stop_pet_travel();
petTravelActive = true;
petTravelAction = PET_TRAVEL_ATTACK;
@@ -596,14 +639,9 @@ void start_pet_travel_attack(int targetPos, const string&in targetLabel, int tar
petTravelDurationMs = get_pet_travel_duration_ms(petTravelStartPos, targetPos, true);
petTravelTimer.restart();
if (petSoundPath != "" && file_exists(petSoundPath)) {
petTravelSoundHandle = play_1d_with_volume_step(
petSoundPath,
get_pet_listener_pos(),
petTravelStartPos,
true,
PLAYER_WEAPON_SOUND_VOLUME_STEP
);
if (petSoundPath != "" && audio_asset_exists(petSoundPath)) {
petTravelSoundHandle = play_1d_with_volume_step(petSoundPath, get_pet_listener_pos(), petTravelStartPos, true,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
}
}
@@ -632,8 +670,10 @@ void start_pet_travel_return(int targetPos) {
}
void request_pet_return() {
if (petLeaving) return;
if (!petActive || !petOut) return;
if (petLeaving)
return;
if (!petActive || !petOut)
return;
if (!petPositionValid) {
petPosition = get_pet_listener_pos();
petPositionValid = true;
@@ -646,8 +686,10 @@ void request_pet_return() {
}
void request_pet_follow() {
if (petLeaving) return;
if (!petActive || !petOut) return;
if (petLeaving)
return;
if (!petActive || !petOut)
return;
petRecallRequested = false;
if (!petPositionValid) {
petPosition = get_pet_listener_pos();
@@ -661,8 +703,10 @@ void request_pet_follow() {
}
void play_pet_recall_ack() {
if (!petActive) return;
if (petSoundPath == "" || !file_exists(petSoundPath)) return;
if (!petActive)
return;
if (petSoundPath == "" || !audio_asset_exists(petSoundPath))
return;
int listenerPos = get_pet_listener_pos();
if (petPositionValid) {
play_1d_with_volume_step(petSoundPath, listenerPos, petPosition, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
@@ -672,8 +716,10 @@ void play_pet_recall_ack() {
}
void update_pet_travel() {
if (!petTravelActive) return;
if (petTravelDurationMs < 1) petTravelDurationMs = 1;
if (!petTravelActive)
return;
if (petTravelDurationMs < 1)
petTravelDurationMs = 1;
if (petTravelAction == PET_TRAVEL_RETURN) {
if (!petPositionValid) {
@@ -697,9 +743,11 @@ void update_pet_travel() {
int stepInterval = walk_speed;
if (distanceToPlayer > PET_FOLLOW_MAX_DISTANCE) {
stepInterval = int(float(walk_speed) / PET_CHARGE_SPEED_MULTIPLIER);
if (stepInterval < 1) stepInterval = 1;
if (stepInterval < 1)
stepInterval = 1;
}
if (stepInterval < PET_TRAVEL_MIN_MS) stepInterval = PET_TRAVEL_MIN_MS;
if (stepInterval < PET_TRAVEL_MIN_MS)
stepInterval = PET_TRAVEL_MIN_MS;
if (petTravelTimer.elapsed < stepInterval) {
return;
@@ -734,7 +782,8 @@ void update_pet_travel() {
int elapsed = petTravelTimer.elapsed;
float progress = float(elapsed) / float(petTravelDurationMs);
if (progress > 1.0f) progress = 1.0f;
if (progress > 1.0f)
progress = 1.0f;
int travel = int(float(petTravelTargetPos - petTravelStartPos) * progress);
int currentPos = petTravelStartPos + travel;
@@ -743,7 +792,14 @@ void update_pet_travel() {
p.update_sound_1d(petTravelSoundHandle, currentPos);
}
if (elapsed < petTravelDurationMs) return;
if (petTravelAction == PET_TRAVEL_LEAVE &&
abs(currentPos - get_pet_listener_pos()) >= PET_LEAVE_DESPAWN_DISTANCE) {
reset_pet_state();
return;
}
if (elapsed < petTravelDurationMs)
return;
safe_destroy_sound(petTravelSoundHandle);
petTravelSoundHandle = -1;
@@ -776,7 +832,7 @@ void update_pet_travel() {
int nextTargetKind = -1;
bool hasNextTarget = find_pet_attack_target(nextTargetPos, nextTargetLabel, nextTargetKind);
if (!hasNextTarget) {
WorldDrop@ drop = find_pet_drop_target();
WorldDrop @drop = find_pet_drop_target();
if (drop !is null) {
petRetrieveTimer.restart();
start_pet_travel_retrieve(drop.position);
@@ -785,7 +841,7 @@ void update_pet_travel() {
request_pet_follow();
}
} else if (petTravelAction == PET_TRAVEL_RETRIEVE) {
WorldDrop@ drop = get_drop_at(petTravelTargetPos);
WorldDrop @drop = get_drop_at(petTravelTargetPos);
if (drop !is null) {
string message = "";
if (try_pet_pickup_world_drop(drop, message)) {
@@ -793,7 +849,7 @@ void update_pet_travel() {
queue_pet_event(message, -1, false);
petPosition = petTravelTargetPos;
petPositionValid = true;
WorldDrop@ nextDrop = find_pet_drop_target();
WorldDrop @nextDrop = find_pet_drop_target();
if (nextDrop !is null) {
petRetrieveTimer.restart();
start_pet_travel_retrieve(nextDrop.position);
@@ -818,10 +874,13 @@ void update_pet_travel() {
stop_pet_travel();
}
bool run_pet_offer_menu(const string&in soundPath, const string&in reasonText) {
if (petActive) return false;
if (soundPath == "" || !file_exists(soundPath)) return false;
if (!has_pet_food_available()) return false;
bool run_pet_offer_menu(const string& in soundPath, const string& in reasonText) {
if (petActive)
return false;
if (soundPath == "" || !audio_asset_exists(soundPath))
return false;
if (!has_pet_food_available())
return false;
string petName = get_pet_name_from_sound_path(soundPath);
string prompt = "A friendly looking " + petName + " begs for food. Accept?";
@@ -848,13 +907,15 @@ bool run_pet_offer_menu(const string&in soundPath, const string&in reasonText) {
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= int(options.length())) selection = 0;
if (selection >= int(options.length()))
selection = 0;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = int(options.length()) - 1;
if (selection < 0)
selection = int(options.length()) - 1;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
@@ -870,35 +931,44 @@ bool run_pet_offer_menu(const string&in soundPath, const string&in reasonText) {
return false;
}
void attempt_pet_offer_random(const string&in reasonText) {
if (petActive) return;
if (!has_pet_food_available()) return;
void attempt_pet_offer_random(const string& in reasonText) {
if (petActive)
return;
if (!has_pet_food_available())
return;
init_pet_sounds();
if (petSoundPaths.length() == 0) return;
if (petSoundPaths.length() == 0)
return;
int pick = random(0, petSoundPaths.length() - 1);
run_pet_offer_menu(petSoundPaths[pick], reasonText);
}
void attempt_pet_offer_from_quest(int score) {
if (score < QUEST_LOG_SCORE) return;
if (score < QUEST_LOG_SCORE)
return;
attempt_pet_offer_random("");
}
void attempt_pet_offer_from_adventure() {
if (petActive) return;
if (random(1, 100) > PET_ADVENTURE_CHANCE) return;
if (petActive)
return;
if (random(1, 100) > PET_ADVENTURE_CHANCE)
return;
attempt_pet_offer_random("");
}
void attempt_pet_offer_from_tree() {
if (petActive) return;
if (random(1, 100) > PET_TREE_HAWK_CHANCE) return;
if (petActive)
return;
if (random(1, 100) > PET_TREE_HAWK_CHANCE)
return;
string hawkSound = get_pet_sound_for_name("hawk");
if (hawkSound == "") return;
if (hawkSound == "")
return;
run_pet_offer_menu(hawkSound, "");
}
bool try_pet_pickup_small_game(const string&in gameType, string &out message) {
bool try_pet_pickup_small_game(const string& in gameType, string& out message) {
if (get_personal_count(ITEM_SMALL_GAME) >= get_personal_stack_limit()) {
message = "You can't carry a " + gameType + ", so you give it to a " + get_pet_display_name() + " to chew on.";
return true;
@@ -909,8 +979,9 @@ bool try_pet_pickup_small_game(const string&in gameType, string &out message) {
return true;
}
bool try_pet_pickup_world_drop(WorldDrop@ drop, string &out message) {
if (drop is null) return false;
bool try_pet_pickup_world_drop(WorldDrop @drop, string& out message) {
if (drop is null)
return false;
if (get_flying_creature_config_by_drop_type(drop.type) !is null) {
return try_pet_pickup_small_game(drop.type, message);
}
@@ -940,13 +1011,14 @@ bool try_pet_pickup_world_drop(WorldDrop@ drop, string &out message) {
return false;
}
WorldDrop@ find_pet_drop_target() {
WorldDrop @find_pet_drop_target() {
int bestDistance = PET_RANGE + 1;
WorldDrop@ best = null;
WorldDrop @best = null;
int origin = get_pet_search_origin();
for (uint i = 0; i < world_drops.length(); i++) {
int distance = abs(world_drops[i].position - origin);
if (distance > PET_RANGE) continue;
if (distance > PET_RANGE)
continue;
if (distance < bestDistance) {
bestDistance = distance;
@best = world_drops[i];
@@ -956,23 +1028,32 @@ WorldDrop@ find_pet_drop_target() {
}
void update_pet_retrieval() {
if (!petActive) return;
if (!petOut) return;
if (petLoyalty <= 0) return;
if (petAdventureMode) return;
if (is_pet_knocked_out()) return;
if (petRetrieveTimer.elapsed < PET_RETRIEVE_COOLDOWN) return;
if (petEventMessages.length() > 2) return;
if (petTravelActive) return;
if (!petActive)
return;
if (!petOut)
return;
if (petLoyalty <= 0)
return;
if (petAdventureMode)
return;
if (is_pet_knocked_out())
return;
if (petRetrieveTimer.elapsed < PET_RETRIEVE_COOLDOWN)
return;
if (petEventMessages.length() > 2)
return;
if (petTravelActive)
return;
WorldDrop@ drop = find_pet_drop_target();
if (drop is null) return;
WorldDrop @drop = find_pet_drop_target();
if (drop is null)
return;
petRetrieveTimer.restart();
start_pet_travel_retrieve(drop.position);
}
bool find_pet_attack_target(int &out targetPos, string &out targetLabel, int &out targetKind) {
bool find_pet_attack_target(int& out targetPos, string& out targetLabel, int& out targetKind) {
int bestDistance = PET_RANGE + 1;
targetPos = -1;
targetLabel = "";
@@ -984,7 +1065,8 @@ bool find_pet_attack_target(int &out targetPos, string &out targetLabel, int &ou
for (uint i = 0; i < bandits.length(); i++) {
int distance = abs(bandits[i].position - origin);
if (distance > PET_RANGE) continue;
if (distance > PET_RANGE)
continue;
if (distance < bestDistance) {
bestDistance = distance;
targetPos = bandits[i].position;
@@ -994,9 +1076,11 @@ bool find_pet_attack_target(int &out targetPos, string &out targetLabel, int &ou
}
for (uint i = 0; i < undeads.length(); i++) {
if (undeads[i].undead_type == "undead_resident") continue;
if (undeads[i].undead_type == "undead_resident")
continue;
int distance = abs(undeads[i].position - origin);
if (distance > PET_RANGE) continue;
if (distance > PET_RANGE)
continue;
if (distance < bestDistance) {
bestDistance = distance;
targetPos = undeads[i].position;
@@ -1007,7 +1091,8 @@ bool find_pet_attack_target(int &out targetPos, string &out targetLabel, int &ou
for (uint i = 0; i < ground_games.length(); i++) {
int distance = abs(ground_games[i].position - origin);
if (distance > PET_RANGE) continue;
if (distance > PET_RANGE)
continue;
if (distance < bestDistance) {
bestDistance = distance;
targetPos = ground_games[i].position;
@@ -1019,7 +1104,7 @@ bool find_pet_attack_target(int &out targetPos, string &out targetLabel, int &ou
return targetPos != -1;
}
bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int &out targetPos) {
bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int& out targetPos) {
int bestDistance = PET_RANGE + 1;
targetPos = -1;
int origin = get_pet_search_origin();
@@ -1032,7 +1117,8 @@ bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int &out t
if (targetKind == 0) {
for (uint i = 0; i < bandits.length(); i++) {
int distanceToOrigin = abs(bandits[i].position - origin);
if (distanceToOrigin > PET_RANGE) continue;
if (distanceToOrigin > PET_RANGE)
continue;
int distance = abs(bandits[i].position - referencePos);
if (distance < bestDistance) {
bestDistance = distance;
@@ -1041,9 +1127,11 @@ bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int &out t
}
} else if (targetKind == 1) {
for (uint i = 0; i < undeads.length(); i++) {
if (undeads[i].undead_type == "undead_resident") continue;
if (undeads[i].undead_type == "undead_resident")
continue;
int distanceToOrigin = abs(undeads[i].position - origin);
if (distanceToOrigin > PET_RANGE) continue;
if (distanceToOrigin > PET_RANGE)
continue;
int distance = abs(undeads[i].position - referencePos);
if (distance < bestDistance) {
bestDistance = distance;
@@ -1053,7 +1141,8 @@ bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int &out t
} else if (targetKind == 2) {
for (uint i = 0; i < ground_games.length(); i++) {
int distanceToOrigin = abs(ground_games[i].position - origin);
if (distanceToOrigin > PET_RANGE) continue;
if (distanceToOrigin > PET_RANGE)
continue;
int distance = abs(ground_games[i].position - referencePos);
if (distance < bestDistance) {
bestDistance = distance;
@@ -1066,61 +1155,84 @@ bool find_pet_attack_target_by_kind(int targetKind, int referencePos, int &out t
}
void update_pet_attack() {
if (!petActive) return;
if (!petOut) return;
if (petLoyalty <= 0) return;
if (is_pet_knocked_out()) return;
if (petAttackTimer.elapsed < PET_ATTACK_COOLDOWN) return;
if (petTravelActive) return;
if (!petActive)
return;
if (!petOut)
return;
if (petLoyalty <= 0)
return;
if (is_pet_knocked_out())
return;
if (petAttackTimer.elapsed < PET_ATTACK_COOLDOWN)
return;
if (petTravelActive)
return;
int targetPos = -1;
string targetLabel = "";
int targetKind = -1;
if (!find_pet_attack_target(targetPos, targetLabel, targetKind)) return;
if (!find_pet_attack_target(targetPos, targetLabel, targetKind))
return;
petAttackTimer.restart();
start_pet_travel_attack(targetPos, targetLabel, targetKind);
}
void update_pet_follow() {
if (!petActive) return;
if (!petOut) return;
if (petAdventureMode) return;
if (is_pet_knocked_out()) return;
if (petTravelActive) return;
if (!petActive)
return;
if (!petOut)
return;
if (petAdventureMode)
return;
if (is_pet_knocked_out())
return;
if (petTravelActive)
return;
WorldDrop@ drop = find_pet_drop_target();
if (drop !is null) return;
WorldDrop @drop = find_pet_drop_target();
if (drop !is null)
return;
int targetPos = -1;
string targetLabel = "";
int targetKind = -1;
if (find_pet_attack_target(targetPos, targetLabel, targetKind)) return;
if (find_pet_attack_target(targetPos, targetLabel, targetKind))
return;
if (is_pet_within_follow_comfort_distance()) return;
if (is_pet_within_follow_comfort_distance())
return;
request_pet_follow();
}
void attempt_pet_random_find() {
if (!petActive) return;
if (!petOut) return;
if (petLoyalty < PET_LOYALTY_BONUS_THRESHOLD) return;
if (random(1, 100) > PET_RANDOM_FIND_CHANCE) return;
if (!petActive)
return;
if (!petOut)
return;
if (petLoyalty < PET_LOYALTY_BONUS_THRESHOLD)
return;
if (random(1, 100) > PET_RANDOM_FIND_CHANCE)
return;
int[] possibleItems = {ITEM_STICKS, ITEM_VINES, ITEM_STONES, ITEM_CLAY};
int itemType = possibleItems[random(0, possibleItems.length() - 1)];
int added = add_to_stack(get_personal_count(itemType), 1);
if (added <= 0) return;
if (added <= 0)
return;
add_personal_count(itemType, added);
string itemName = (added == 1) ? item_registry[itemType].singular : item_registry[itemType].name;
queue_pet_event("Your " + get_pet_display_name() + " retrieved " + added + " " + itemName + ".", petPositionValid ? petPosition : x, false);
queue_pet_event("Your " + get_pet_display_name() + " retrieved " + added + " " + itemName + ".",
petPositionValid ? petPosition : x, false);
request_pet_follow();
}
void handle_pet_hourly_update(int hour) {
if (!petActive) return;
if (petLeaving) return;
if (!petActive)
return;
if (petLeaving)
return;
if (petKnockoutHoursRemaining > 0) {
petKnockoutHoursRemaining--;
@@ -1133,12 +1245,14 @@ void handle_pet_hourly_update(int hour) {
if (petKnockoutHoursRemaining <= 0 && !petOut && petHealth > 0 && petHealth < PET_HEALTH_MAX) {
petHealth += 1;
if (petHealth > PET_HEALTH_MAX) petHealth = PET_HEALTH_MAX;
if (petHealth > PET_HEALTH_MAX)
petHealth = PET_HEALTH_MAX;
}
if (petOut) {
adjust_pet_loyalty(-1);
if (!petActive || petLeaving) return;
if (!petActive || petLeaving)
return;
if (petLoyalty <= 1 && !petHungryWarned) {
notify("A " + get_pet_display_name() + " is getting hungry.");
petHungryWarned = true;
+64 -36
View File
@@ -16,11 +16,16 @@ int[] quest_queue;
bool quest_roll_done_today = false;
string get_quest_name(int quest_type) {
if (quest_type == QUEST_BAT_INVASION) return "Bat Invasion";
if (quest_type == QUEST_CATCH_BOOMERANG) return "Catch the Boomerang";
if (quest_type == QUEST_ENCHANTED_MELODY) return "Enchanted Melody";
if (quest_type == QUEST_ESCAPE_FROM_HEL) return "Escape from Hel";
if (quest_type == QUEST_SKELETAL_BARD) return "Skeletal Bard";
if (quest_type == QUEST_BAT_INVASION)
return "Bat Invasion";
if (quest_type == QUEST_CATCH_BOOMERANG)
return "Catch the Boomerang";
if (quest_type == QUEST_ENCHANTED_MELODY)
return "Enchanted Melody";
if (quest_type == QUEST_ESCAPE_FROM_HEL)
return "Escape from Hel";
if (quest_type == QUEST_SKELETAL_BARD)
return "Skeletal Bard";
return "Unknown Quest";
}
@@ -45,8 +50,10 @@ string get_quest_description(int quest_type) {
int get_quest_chance_from_favor() {
int chance = int(favor * QUEST_CHANCE_PER_FAVOR);
if (chance < QUEST_MIN_CHANCE && favor >= 1.0) chance = QUEST_MIN_CHANCE;
if (chance > 100) chance = 100;
if (chance < QUEST_MIN_CHANCE && favor >= 1.0)
chance = QUEST_MIN_CHANCE;
if (chance > 100)
chance = 100;
return chance;
}
@@ -59,21 +66,27 @@ void quest_boomerang_hit_sound() {
}
void add_quest(int quest_type) {
if (quest_queue.length() >= QUEST_MAX_ACTIVE) return;
if (quest_queue.length() >= QUEST_MAX_ACTIVE)
return;
quest_queue.insert_last(quest_type);
notify("A new quest is available: " + get_quest_name(quest_type) + ".");
}
void attempt_daily_quest() {
if (quest_roll_done_today) return;
if (favor < 1.0) return;
if (world_altars.length() == 0) return;
if (quest_queue.length() >= QUEST_MAX_ACTIVE) return;
if (quest_roll_done_today)
return;
if (favor < 1.0)
return;
if (world_altars.length() == 0)
return;
if (quest_queue.length() >= QUEST_MAX_ACTIVE)
return;
quest_roll_done_today = true;
int chance = get_quest_chance_from_favor();
int roll = random(1, 100);
if (roll > chance) return;
if (roll > chance)
return;
int quest_type = random(0, QUEST_TYPE_COUNT - 1);
add_quest(quest_type);
@@ -94,18 +107,24 @@ void check_quest_menu() {
}
string get_quest_favor_phrase(int score) {
if (score <= 2) return "The gods are displeased with your performance.";
if (score < QUEST_STONE_SCORE) return "The gods are pleased with your performance.";
if (score <= 2)
return "The gods are displeased with your performance.";
if (score < QUEST_STONE_SCORE)
return "The gods are pleased with your performance.";
int extreme_threshold = QUEST_LOG_SCORE - 2;
if (score < extreme_threshold) return "The gods are very pleased with your performance.";
if (score < QUEST_LOG_SCORE) return "The gods are extremely pleased with your performance.";
if (score < extreme_threshold)
return "The gods are very pleased with your performance.";
if (score < QUEST_LOG_SCORE)
return "The gods are extremely pleased with your performance.";
return "The gods are ultimately pleased with your performance.";
}
void apply_quest_reward(int score) {
double favor_gain = score * QUEST_FAVOR_PER_POINT;
if (favor_gain < 0) favor_gain = 0;
if (favor_gain > 1.0) favor_gain = 1.0;
if (favor_gain < 0)
favor_gain = 0;
if (favor_gain > 1.0)
favor_gain = 1.0;
favor += favor_gain;
// Determine quantity based on score
@@ -115,17 +134,19 @@ void apply_quest_reward(int score) {
// 8-9: 3
// >= 10: 4
int quantity = 0;
if (score >= QUEST_LOG_SCORE) quantity = 4;
else if (score >= QUEST_LOG_SCORE - 2) quantity = 3;
else if (score >= QUEST_STONE_SCORE) quantity = 2;
else if (score > 2) quantity = 1;
if (score >= QUEST_LOG_SCORE)
quantity = 4;
else if (score >= QUEST_LOG_SCORE - 2)
quantity = 3;
else if (score >= QUEST_STONE_SCORE)
quantity = 2;
else if (score > 2)
quantity = 1;
// Select reward item
int[] possible_rewards = {
ITEM_STICKS, ITEM_VINES, ITEM_REEDS, ITEM_STONES, ITEM_LOGS, ITEM_CLAY,
ITEM_MEAT, ITEM_SKINS, ITEM_FEATHERS, ITEM_DOWN, ITEM_FISH, ITEM_SMOKED_FISH,
ITEM_HEAL_SCROLL, ITEM_INCENSE, ITEM_BASKET_FOOD
};
int[] possible_rewards = {ITEM_STICKS, ITEM_VINES, ITEM_REEDS, ITEM_STONES, ITEM_LOGS,
ITEM_CLAY, ITEM_MEAT, ITEM_SKINS, ITEM_FEATHERS, ITEM_DOWN,
ITEM_FISH, ITEM_SMOKED_FISH, ITEM_HEAL_SCROLL, ITEM_INCENSE, ITEM_BASKET_FOOD};
int reward_item = possible_rewards[random(0, possible_rewards.length() - 1)];
int added_amount = 0;
@@ -161,11 +182,16 @@ void apply_quest_reward(int score) {
void run_quest(int quest_type) {
p.pause_all();
int score = 0;
if (quest_type == QUEST_BAT_INVASION) score = run_bat_invasion();
else if (quest_type == QUEST_CATCH_BOOMERANG) score = run_catch_the_boomerang();
else if (quest_type == QUEST_ENCHANTED_MELODY) score = run_enchanted_melody();
else if (quest_type == QUEST_ESCAPE_FROM_HEL) score = run_escape_from_hel();
else if (quest_type == QUEST_SKELETAL_BARD) score = run_skeletal_bard();
if (quest_type == QUEST_BAT_INVASION)
score = run_bat_invasion();
else if (quest_type == QUEST_CATCH_BOOMERANG)
score = run_catch_the_boomerang();
else if (quest_type == QUEST_ENCHANTED_MELODY)
score = run_enchanted_melody();
else if (quest_type == QUEST_ESCAPE_FROM_HEL)
score = run_escape_from_hel();
else if (quest_type == QUEST_SKELETAL_BARD)
score = run_skeletal_bard();
if (return_to_main_menu_requested) {
p.resume_all();
return;
@@ -183,7 +209,7 @@ void run_quest_menu() {
options.insert_last(get_quest_name(quest_queue[i]));
}
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -198,7 +224,8 @@ void run_quest_menu() {
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= options.length()) selection = 0;
if (selection >= options.length())
selection = 0;
count_str = " " + (selection + 1) + " of " + options.length();
speak_with_history(options[selection] + count_str, true);
}
@@ -206,7 +233,8 @@ void run_quest_menu() {
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = options.length() - 1;
if (selection < 0)
selection = options.length() - 1;
count_str = " " + (selection + 1) + " of " + options.length();
speak_with_history(options[selection] + count_str, true);
}
+6 -3
View File
@@ -60,12 +60,15 @@ int run_catch_the_boomerang() {
if (key_pressed(KEY_SPACE)) {
if (returning && boomerangY > -5) {
int points = 5 + boomerangY;
if (points < 1) points = 1;
if (points > 4) points = 4;
if (points < 1)
points = 1;
if (points > 4)
points = 4;
score += points;
caughtCount++;
string promptSuffix = (turn < turnsTotal - 1) ? " Press Space to throw." : "";
speak_with_history("You " + skillLevel[points] + " the boomerang. " + points + " points." + promptSuffix, true);
speak_with_history(
"You " + skillLevel[points] + " the boomerang. " + points + " points." + promptSuffix, true);
} else {
string promptSuffix = (turn < turnsTotal - 1) ? " Press Space to throw." : "";
speak_with_history("You missed the boomerang." + promptSuffix, true);
+14 -12
View File
@@ -1,21 +1,22 @@
// Enchanted Melody quest game
string[] quest_notes = {
"sounds/quests/bone1.ogg",
"sounds/quests/bone2.ogg",
"sounds/quests/bone3.ogg",
"sounds/quests/bone4.ogg"
};
string[] quest_notes = {"sounds/quests/bone1.ogg", "sounds/quests/bone2.ogg", "sounds/quests/bone3.ogg",
"sounds/quests/bone4.ogg"};
void play_note(int note_index) {
if (note_index < 0 || note_index >= int(quest_notes.length())) return;
if (note_index < 0 || note_index >= int(quest_notes.length()))
return;
p.play_stationary(quest_notes[note_index], false);
}
int get_note_from_key() {
if (key_pressed(KEY_F) || key_pressed(KEY_K)) return 0;
if (key_pressed(KEY_D) || key_pressed(KEY_J)) return 1;
if (key_pressed(KEY_R) || key_pressed(KEY_I)) return 2;
if (key_pressed(KEY_E) || key_pressed(KEY_U)) return 3;
if (key_pressed(KEY_F) || key_pressed(KEY_K))
return 0;
if (key_pressed(KEY_D) || key_pressed(KEY_J))
return 1;
if (key_pressed(KEY_R) || key_pressed(KEY_I))
return 2;
if (key_pressed(KEY_E) || key_pressed(KEY_U))
return 3;
return -1;
}
@@ -89,7 +90,8 @@ int run_enchanted_melody() {
wait(5);
handle_global_volume_keys();
int note = get_note_from_key();
if (note == -1) continue;
if (note == -1)
continue;
play_note(note);
if (note != pattern[index]) {
int score = rounds * 2;
+2 -1
View File
@@ -42,7 +42,8 @@ int run_escape_from_hel() {
while (true) {
// Speed increases indefinitely until player can't keep up
int step_time = base_step_time - (total_steps * 8);
if (step_time < 50) step_time = 50; // Minimum to prevent audio/timing issues
if (step_time < 50)
step_time = 50; // Minimum to prevent audio/timing issues
handle_global_volume_keys();
+14 -15
View File
@@ -1,14 +1,7 @@
// Skeletal Bard quest game
string[] skeletalBardNotes = {
"sounds/quests/bone1.ogg",
"sounds/quests/bone2.ogg",
"sounds/quests/bone3.ogg",
"sounds/quests/bone4.ogg",
"sounds/quests/bone5.ogg",
"sounds/quests/bone6.ogg",
"sounds/quests/bone7.ogg",
"sounds/quests/bone8.ogg"
};
string[] skeletalBardNotes = {"sounds/quests/bone1.ogg", "sounds/quests/bone2.ogg", "sounds/quests/bone3.ogg",
"sounds/quests/bone4.ogg", "sounds/quests/bone5.ogg", "sounds/quests/bone6.ogg",
"sounds/quests/bone7.ogg", "sounds/quests/bone8.ogg"};
void play_skeletal_bard_note() {
int noteIndex = random(0, skeletalBardNotes.length() - 1);
@@ -26,12 +19,14 @@ int select_note_count(int minNotes, int maxNotes, int startValue) {
}
if (key_pressed(KEY_UP)) {
if (selection < maxNotes) selection++;
if (selection < maxNotes)
selection++;
speak_with_history("" + selection + ".", true);
}
if (key_pressed(KEY_DOWN)) {
if (selection > minNotes) selection--;
if (selection > minNotes)
selection--;
speak_with_history("" + selection + ".", true);
}
@@ -78,13 +73,17 @@ int run_skeletal_bard() {
return 0;
}
int diff = length - guess;
if (diff < 0) diff = -diff;
if (diff < 0)
diff = -diff;
int points = 4 - diff;
if (points < 0) points = 0;
if (points < 0)
points = 0;
score += points;
speak_with_history("You entered " + guess + " notes and the actual number was " + length + ". " + points + " points. Press Enter to continue.", true);
speak_with_history("You entered " + guess + " notes and the actual number was " + length + ". " + points +
" points. Press Enter to continue.",
true);
while (true) {
wait(5);
handle_global_volume_keys();
+66 -31
View File
@@ -38,15 +38,19 @@ int equipped_weapon_rune = RUNE_NONE;
// Get display name for a rune type
string get_rune_name(int rune_type) {
if (rune_type == RUNE_SWIFTNESS) return "Rune of Swiftness";
if (rune_type == RUNE_DESTRUCTION) return "Rune of Destruction";
if (rune_type == RUNE_SWIFTNESS)
return "Rune of Swiftness";
if (rune_type == RUNE_DESTRUCTION)
return "Rune of Destruction";
return "Unknown Rune";
}
// Get the effect suffix for runed item names (e.g., "of Quickness")
string get_rune_effect_name(int rune_type) {
if (rune_type == RUNE_SWIFTNESS) return "Quickness";
if (rune_type == RUNE_DESTRUCTION) return "Destruction";
if (rune_type == RUNE_SWIFTNESS)
return "Quickness";
if (rune_type == RUNE_DESTRUCTION)
return "Destruction";
return "Unknown";
}
@@ -57,23 +61,29 @@ bool any_rune_unlocked() {
// Check if a specific rune is unlocked
bool is_rune_unlocked(int rune_type) {
if (rune_type == RUNE_SWIFTNESS) return rune_swiftness_unlocked;
if (rune_type == RUNE_DESTRUCTION) return rune_destruction_unlocked;
if (rune_type == RUNE_SWIFTNESS)
return rune_swiftness_unlocked;
if (rune_type == RUNE_DESTRUCTION)
return rune_destruction_unlocked;
return false;
}
void get_all_rune_types(int[]@ runeTypes) {
if (@runeTypes == null) return;
void get_all_rune_types(int[] @runeTypes) {
if (@runeTypes == null)
return;
runeTypes.resize(0);
runeTypes.insert_last(RUNE_SWIFTNESS);
runeTypes.insert_last(RUNE_DESTRUCTION);
}
void get_unlocked_rune_types(int[]@ runeTypes) {
if (@runeTypes == null) return;
void get_unlocked_rune_types(int[] @runeTypes) {
if (@runeTypes == null)
return;
runeTypes.resize(0);
if (rune_swiftness_unlocked) runeTypes.insert_last(RUNE_SWIFTNESS);
if (rune_destruction_unlocked) runeTypes.insert_last(RUNE_DESTRUCTION);
if (rune_swiftness_unlocked)
runeTypes.insert_last(RUNE_SWIFTNESS);
if (rune_destruction_unlocked)
runeTypes.insert_last(RUNE_DESTRUCTION);
}
// Create dictionary key for runed item storage
@@ -111,7 +121,8 @@ bool has_any_runed_version(int equip_type) {
int[] runeTypes;
get_all_rune_types(runeTypes);
for (uint i = 0; i < runeTypes.length(); i++) {
if (get_runed_item_count(equip_type, runeTypes[i]) > 0) return true;
if (get_runed_item_count(equip_type, runeTypes[i]) > 0)
return true;
}
return false;
}
@@ -144,7 +155,8 @@ void remove_stored_runed_item(int equip_type, int rune_type) {
// Deposit runed item from personal inventory to storage
bool deposit_runed_item(int equip_type, int rune_type) {
int personal = get_runed_item_count(equip_type, rune_type);
if (personal <= 0) return false;
if (personal <= 0)
return false;
remove_runed_item(equip_type, rune_type);
add_stored_runed_item(equip_type, rune_type);
@@ -154,7 +166,8 @@ bool deposit_runed_item(int equip_type, int rune_type) {
// Withdraw runed item from storage to personal inventory
bool withdraw_runed_item(int equip_type, int rune_type) {
int stored = get_stored_runed_item_count(equip_type, rune_type);
if (stored <= 0) return false;
if (stored <= 0)
return false;
remove_stored_runed_item(equip_type, rune_type);
add_runed_item(equip_type, rune_type);
@@ -163,32 +176,54 @@ bool withdraw_runed_item(int equip_type, int rune_type) {
// Get the rune type on equipped item for a given slot
int get_equipped_rune_for_slot(int equip_type) {
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE ||
equip_type == EQUIP_SLING || equip_type == EQUIP_BOW) {
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE || equip_type == EQUIP_SLING || equip_type == EQUIP_BOW) {
return equipped_weapon_rune;
}
if (equip_type == EQUIP_HAT) return equipped_head_rune;
if (equip_type == EQUIP_TUNIC) return equipped_torso_rune;
if (equip_type == EQUIP_POUCH || equip_type == EQUIP_BACKPACK) return equipped_arms_rune;
if (equip_type == EQUIP_GLOVES) return equipped_hands_rune;
if (equip_type == EQUIP_PANTS) return equipped_legs_rune;
if (equip_type == EQUIP_MOCCASINS) return equipped_feet_rune;
if (equip_type == EQUIP_HAT)
return equipped_head_rune;
if (equip_type == EQUIP_TUNIC)
return equipped_torso_rune;
if (equip_type == EQUIP_POUCH || equip_type == EQUIP_BACKPACK)
return equipped_arms_rune;
if (equip_type == EQUIP_GLOVES)
return equipped_hands_rune;
if (equip_type == EQUIP_PANTS)
return equipped_legs_rune;
if (equip_type == EQUIP_MOCCASINS)
return equipped_feet_rune;
return RUNE_NONE;
}
// Set the rune on an equipped item slot
void set_equipped_rune_for_slot(int equip_type, int rune_type) {
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE ||
equip_type == EQUIP_SLING || equip_type == EQUIP_BOW) {
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE || equip_type == EQUIP_SLING || equip_type == EQUIP_BOW) {
equipped_weapon_rune = rune_type;
return;
}
if (equip_type == EQUIP_HAT) { equipped_head_rune = rune_type; return; }
if (equip_type == EQUIP_TUNIC) { equipped_torso_rune = rune_type; return; }
if (equip_type == EQUIP_POUCH || equip_type == EQUIP_BACKPACK) { equipped_arms_rune = rune_type; return; }
if (equip_type == EQUIP_GLOVES) { equipped_hands_rune = rune_type; return; }
if (equip_type == EQUIP_PANTS) { equipped_legs_rune = rune_type; return; }
if (equip_type == EQUIP_MOCCASINS) { equipped_feet_rune = rune_type; return; }
if (equip_type == EQUIP_HAT) {
equipped_head_rune = rune_type;
return;
}
if (equip_type == EQUIP_TUNIC) {
equipped_torso_rune = rune_type;
return;
}
if (equip_type == EQUIP_POUCH || equip_type == EQUIP_BACKPACK) {
equipped_arms_rune = rune_type;
return;
}
if (equip_type == EQUIP_GLOVES) {
equipped_hands_rune = rune_type;
return;
}
if (equip_type == EQUIP_PANTS) {
equipped_legs_rune = rune_type;
return;
}
if (equip_type == EQUIP_MOCCASINS) {
equipped_feet_rune = rune_type;
return;
}
}
// Clear rune from an equipped slot
+50 -25
View File
@@ -8,13 +8,20 @@ int get_total_rune_walk_speed_bonus() {
int bonus = 0;
// Check each equipment slot for swiftness runes
if (equipped_head_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_torso_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_arms_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_hands_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_legs_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_feet_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_weapon_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_head_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_torso_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_arms_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_hands_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_legs_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_feet_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
if (equipped_weapon_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_SPEED_BONUS;
return bonus;
}
@@ -25,13 +32,20 @@ int get_total_rune_gather_bonus() {
int bonus = 0;
// Check each equipment slot for swiftness runes
if (equipped_head_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_torso_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_arms_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_hands_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_legs_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_feet_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_weapon_rune == RUNE_SWIFTNESS) bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_head_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_torso_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_arms_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_hands_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_legs_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_feet_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
if (equipped_weapon_rune == RUNE_SWIFTNESS)
bonus += RUNE_SWIFTNESS_GATHER_BONUS;
return bonus;
}
@@ -43,10 +57,12 @@ int apply_rune_gather_bonus(int base_time) {
if (blessing_search_active) {
bonus_percent += BLESSING_SEARCH_GATHER_BONUS;
}
if (bonus_percent <= 0) return base_time;
if (bonus_percent <= 0)
return base_time;
// Keep gathering from becoming instant.
if (bonus_percent > GATHER_TIME_REDUCTION_CAP) bonus_percent = GATHER_TIME_REDUCTION_CAP;
if (bonus_percent > GATHER_TIME_REDUCTION_CAP)
bonus_percent = GATHER_TIME_REDUCTION_CAP;
int reduction = (base_time * bonus_percent) / 100;
return base_time - reduction;
@@ -55,13 +71,20 @@ int apply_rune_gather_bonus(int base_time) {
// Count total equipped swiftness runes
int count_equipped_swiftness_runes() {
int count = 0;
if (equipped_head_rune == RUNE_SWIFTNESS) count++;
if (equipped_torso_rune == RUNE_SWIFTNESS) count++;
if (equipped_arms_rune == RUNE_SWIFTNESS) count++;
if (equipped_hands_rune == RUNE_SWIFTNESS) count++;
if (equipped_legs_rune == RUNE_SWIFTNESS) count++;
if (equipped_feet_rune == RUNE_SWIFTNESS) count++;
if (equipped_weapon_rune == RUNE_SWIFTNESS) count++;
if (equipped_head_rune == RUNE_SWIFTNESS)
count++;
if (equipped_torso_rune == RUNE_SWIFTNESS)
count++;
if (equipped_arms_rune == RUNE_SWIFTNESS)
count++;
if (equipped_hands_rune == RUNE_SWIFTNESS)
count++;
if (equipped_legs_rune == RUNE_SWIFTNESS)
count++;
if (equipped_feet_rune == RUNE_SWIFTNESS)
count++;
if (equipped_weapon_rune == RUNE_SWIFTNESS)
count++;
return count;
}
@@ -79,14 +102,16 @@ string get_rune_speed_description() {
desc += walk_bonus + "ms faster walking";
}
if (gather_bonus > 0) {
if (desc.length() > 0) desc += ", ";
if (desc.length() > 0)
desc += ", ";
desc += gather_bonus + "% faster gathering";
}
return desc;
}
int apply_weapon_rune_damage(int baseDamage) {
if (baseDamage <= 0) return baseDamage;
if (baseDamage <= 0)
return baseDamage;
if (equipped_weapon_rune == RUNE_DESTRUCTION) {
return baseDamage * RUNE_DESTRUCTION_DAMAGE_MULTIPLIER;
}
+407 -178
View File
File diff suppressed because it is too large Load Diff
+7 -4
View File
@@ -4,14 +4,17 @@ string get_terrain_at_position(int posX) {
return "water";
}
MountainRange@ mountain = get_mountain_at(posX);
MountainRange @mountain = get_mountain_at(posX);
if (mountain !is null) {
return mountain.get_terrain_at(posX);
}
if (posX <= BASE_END) return "wood";
if (posX <= GRASS_END) return "grass";
if (posX <= GRAVEL_END) return "gravel";
if (posX <= BASE_END)
return "wood";
if (posX <= GRASS_END)
return "grass";
if (posX <= GRAVEL_END)
return "gravel";
int index = posX - expanded_area_start;
if (index >= 0 && index < int(expanded_terrain_types.length())) {
+161 -85
View File
@@ -95,15 +95,17 @@ void reset_player_item_break_state() {
reset_player_item_break_audio_state();
}
void queue_player_item_break_message(const string&in message) {
if (message.length() == 0) return;
void queue_player_item_break_message(const string& in message) {
if (message.length() == 0)
return;
playerItemBreakMessage = message;
playerItemBreakSoundHandle = p.play_stationary("sounds/items/item_breaks.ogg", false);
playerItemBreakSoundPending = true;
}
void update_player_item_break_message() {
if (!playerItemBreakSoundPending) return;
if (!playerItemBreakSoundPending)
return;
if (playerItemBreakSoundHandle != -1 && p.sound_is_active(playerItemBreakSoundHandle)) {
return;
}
@@ -116,8 +118,10 @@ void update_player_item_break_message() {
}
void resolve_pending_player_item_break() {
if (!playerItemBreakPending) return;
if (x > BASE_END) return;
if (!playerItemBreakPending)
return;
if (x > BASE_END)
return;
if (playerItemBreakPendingType == -1) {
playerItemBreakPending = false;
return;
@@ -132,12 +136,15 @@ void resolve_pending_player_item_break() {
}
void attempt_player_item_break_check() {
if (playerItemBreakPending) return;
if (playerItemBreaksToday >= PLAYER_ITEM_BREAKS_PER_DAY) return;
if (playerItemBreakPending)
return;
if (playerItemBreaksToday >= PLAYER_ITEM_BREAKS_PER_DAY)
return;
int[] breakableItems;
get_breakable_personal_item_types(breakableItems);
if (breakableItems.length() == 0) return;
if (breakableItems.length() == 0)
return;
int roll = random(1, PLAYER_ITEM_BREAK_ROLL_MAX);
int checkChance = int(playerItemBreakChance); // Floor for comparison
@@ -167,7 +174,7 @@ void attempt_player_item_break_check() {
}
}
string get_invasion_enemy_type_for_terrain(const string&in terrain_type) {
string get_invasion_enemy_type_for_terrain(const string& in terrain_type) {
for (uint i = 0; i < invasion_terrain_enemy_map.length(); i++) {
string entry = invasion_terrain_enemy_map[i];
int eq_pos = entry.find("=");
@@ -184,12 +191,13 @@ string get_invasion_enemy_type_for_terrain(const string&in terrain_type) {
return default_invasion_enemy_type;
}
string get_invasion_enemy_label(const string&in enemy_type) {
if (enemy_type != "") return enemy_type;
string get_invasion_enemy_label(const string& in enemy_type) {
if (enemy_type != "")
return enemy_type;
return default_invasion_enemy_type;
}
string get_invasion_enemy_plural(const string&in enemy_type) {
string get_invasion_enemy_plural(const string& in enemy_type) {
return get_invasion_enemy_label(enemy_type) + "s";
}
@@ -257,11 +265,18 @@ string expand_regular_area() {
// Fill the new area up to its tree cap with proper spacing
spawn_trees(new_start, new_end);
} else {
// Keep both extreme edge tiles dry so area transitions are never blocked.
int max_stream_width = EXPANSION_SIZE - 2;
if (max_stream_width > 0) {
int stream_width = random(1, 5);
int stream_start = random(0, EXPANSION_SIZE - stream_width);
if (stream_width > max_stream_width) {
stream_width = max_stream_width;
}
int stream_start = random(1, EXPANSION_SIZE - stream_width - 1);
int actual_start = new_start + stream_start;
add_world_stream(actual_start, stream_width);
}
}
area_expanded_today = true;
notify("The area has expanded! New territory discovered to the east.");
@@ -280,7 +295,7 @@ void expand_mountain() {
MAP_SIZE += size;
// Generate mountain range
MountainRange@ mountain = MountainRange(new_start, size);
MountainRange @mountain = MountainRange(new_start, size);
world_mountains.insert_last(mountain);
// Fill terrain types array for compatibility with save system
@@ -343,14 +358,17 @@ void update_invasion_chance_for_new_day() {
invasion_chance = 25;
} else {
invasion_chance += 25;
if (invasion_chance > 100) invasion_chance = 100;
if (invasion_chance > 100)
invasion_chance = 100;
}
}
}
int get_random_invasion_hour(int min_hour) {
if (min_hour < 6) min_hour = 6;
if (min_hour > 11) return -1;
if (min_hour < 6)
min_hour = 6;
if (min_hour > 11)
return -1;
return random(min_hour, 11);
}
@@ -359,7 +377,8 @@ bool is_night_hour(int hour) {
}
int get_random_zombie_swarm_hour(int min_hour) {
if (!is_night_hour(min_hour)) return -1;
if (!is_night_hour(min_hour))
return -1;
if (min_hour >= 19) {
return random(min_hour, 23);
}
@@ -367,14 +386,17 @@ int get_random_zombie_swarm_hour(int min_hour) {
}
void schedule_invasion() {
if (invasion_scheduled_hour != -1) return;
if (invasion_scheduled_hour != -1)
return;
int hour = get_random_invasion_hour(current_hour);
if (hour == -1) return;
if (hour == -1)
return;
invasion_scheduled_hour = hour;
}
void check_scheduled_invasion() {
if (invasion_active) return;
if (invasion_active)
return;
// Check scheduled invasion regardless of triggered flag (fixes bug where flag was set early in old saves)
if (invasion_scheduled_hour != -1) {
@@ -388,19 +410,25 @@ void check_scheduled_invasion() {
return;
}
if (invasion_triggered_today) return;
if (invasion_triggered_today)
return;
}
void attempt_daily_invasion() {
if (current_day < 2) return;
if (invasion_triggered_today || invasion_active) return;
if (invasion_roll_done_today) return;
if (current_hour < 6 || current_hour > 12) return;
if (current_day < 2)
return;
if (invasion_triggered_today || invasion_active)
return;
if (invasion_roll_done_today)
return;
if (current_hour < 6 || current_hour > 12)
return;
invasion_roll_done_today = true;
int roll = random(1, 100);
if (roll > invasion_chance) return;
if (roll > invasion_chance)
return;
schedule_invasion();
check_scheduled_invasion();
@@ -412,20 +440,25 @@ bool can_roll_zombie_swarm_today() {
int get_zombie_swarm_duration_hours() {
int offset = current_day - ZOMBIE_SWARM_START_DAY;
if (offset < 0) offset = 0;
if (offset < 0)
offset = 0;
int cycles = offset / ZOMBIE_SWARM_INTERVAL_DAYS;
int duration = ZOMBIE_SWARM_BASE_DURATION_HOURS + (cycles * ZOMBIE_SWARM_DURATION_STEP_HOURS);
if (duration < 1) duration = 1;
if (duration < 1)
duration = 1;
return duration;
}
int get_zombie_swarm_chance_for_day() {
int offset = current_day - ZOMBIE_SWARM_START_DAY;
if (offset < 0) offset = 0;
if (offset < 0)
offset = 0;
int cycles = offset / ZOMBIE_SWARM_CHANCE_INTERVAL_DAYS;
int chance = ZOMBIE_SWARM_CHANCE_START + (cycles * ZOMBIE_SWARM_CHANCE_STEP);
if (chance > ZOMBIE_SWARM_CHANCE_CAP) chance = ZOMBIE_SWARM_CHANCE_CAP;
if (chance < 0) chance = 0;
if (chance > ZOMBIE_SWARM_CHANCE_CAP)
chance = ZOMBIE_SWARM_CHANCE_CAP;
if (chance < 0)
chance = 0;
return chance;
}
@@ -443,7 +476,8 @@ void end_zombie_swarm() {
}
void check_zombie_swarm_status() {
if (!zombie_swarm_active) return;
if (!zombie_swarm_active)
return;
if (!is_night_hour(current_hour)) {
end_zombie_swarm();
return;
@@ -458,14 +492,17 @@ void check_zombie_swarm_status() {
}
void schedule_zombie_swarm() {
if (zombie_swarm_scheduled_hour != -1) return;
if (zombie_swarm_scheduled_hour != -1)
return;
int hour = get_random_zombie_swarm_hour(current_hour);
if (hour == -1) return;
if (hour == -1)
return;
zombie_swarm_scheduled_hour = hour;
}
void check_scheduled_zombie_swarm() {
if (zombie_swarm_active) return;
if (zombie_swarm_active)
return;
if (zombie_swarm_scheduled_hour != -1) {
if (!is_night_hour(zombie_swarm_scheduled_hour) || !is_night_hour(current_hour)) {
zombie_swarm_scheduled_hour = -1;
@@ -478,13 +515,17 @@ void check_scheduled_zombie_swarm() {
}
return;
}
if (zombie_swarm_triggered_today) return;
if (zombie_swarm_triggered_today)
return;
}
void attempt_daily_zombie_swarm() {
if (!can_roll_zombie_swarm_today()) return;
if (zombie_swarm_roll_done_today || zombie_swarm_triggered_today || zombie_swarm_active) return;
if (!is_night_hour(current_hour)) return;
if (!can_roll_zombie_swarm_today())
return;
if (zombie_swarm_roll_done_today || zombie_swarm_triggered_today || zombie_swarm_active)
return;
if (!is_night_hour(current_hour))
return;
zombie_swarm_roll_done_today = true;
int chance = get_zombie_swarm_chance_for_day();
@@ -503,13 +544,15 @@ void attempt_daily_zombie_swarm() {
check_scheduled_zombie_swarm();
}
void get_expanded_area_segments(int[]@ areaStarts, int[]@ areaEnds, string[]@ areaTypes) {
void get_expanded_area_segments(int[] @areaStarts, int[] @areaEnds, string[] @areaTypes) {
areaStarts.resize(0);
areaEnds.resize(0);
areaTypes.resize(0);
if (expanded_area_start == -1) return;
if (expanded_area_start == -1)
return;
int total = int(expanded_terrain_types.length());
if (total <= 0) return;
if (total <= 0)
return;
string current_type = get_expanded_area_type(0);
int segment_start = 0;
@@ -530,21 +573,28 @@ void get_expanded_area_segments(int[]@ areaStarts, int[]@ areaEnds, string[]@ ar
}
void attempt_expansion_roamer_spawn() {
if (!is_daytime) return;
if (invasion_active) return;
if (!invasion_started_once) return;
if (expanded_area_start == -1) return;
if (current_hour % EXPANSION_ROAMER_SPAWN_INTERVAL_HOURS != 0) return;
if (!is_daytime)
return;
if (invasion_active)
return;
if (!invasion_started_once)
return;
if (expanded_area_start == -1)
return;
if (current_hour % EXPANSION_ROAMER_SPAWN_INTERVAL_HOURS != 0)
return;
int[] areaStarts;
int[] areaEnds;
string[] areaTypes;
get_expanded_area_segments(areaStarts, areaEnds, areaTypes);
if (areaStarts.length() == 0) return;
if (areaStarts.length() == 0)
return;
for (uint i = 0; i < areaStarts.length(); i++) {
int count = count_bandits_in_range(areaStarts[i], areaEnds[i]);
if (count >= EXPANSION_ROAMER_MAX_PER_AREA) continue;
if (count >= EXPANSION_ROAMER_MAX_PER_AREA)
continue;
string invader_type = get_invasion_enemy_type_for_terrain(areaTypes[i]);
spawn_bandit(areaStarts[i], areaEnds[i], invader_type);
}
@@ -588,7 +638,8 @@ void attempt_resident_recruitment() {
added = MAX_RESIDENTS - residents_count;
}
if (added <= 0) return;
if (added <= 0)
return;
residents_count += added;
string join_message = (added == 1) ? "A survivor joins your base." : "" + added + " survivors join your base.";
@@ -617,13 +668,15 @@ void transition_bandits_to_wandering() {
}
bandits[i].behavior_state = "wandering";
bandits[i].wander_direction = random(-1, 1);
bandits[i].wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
bandits[i].wander_direction_change_interval =
random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
bandits[i].wander_direction_timer.restart();
}
}
void check_invasion_status() {
if (!invasion_active) return;
if (!invasion_active)
return;
// Check if invasion duration has elapsed
int hours_elapsed = current_hour - invasion_start_hour;
@@ -669,32 +722,40 @@ void update_blessings() {
}
void attempt_blessing() {
if (favor < 1.0) return;
if (favor < 1.0)
return;
int roll = random(1, 100);
if (roll > BLESSING_TRIGGER_CHANCE) return;
if (roll > BLESSING_TRIGGER_CHANCE)
return;
int[] options;
if (player_health < max_health) options.insert_last(0);
if (!blessing_speed_active) options.insert_last(1);
if (barricade_health < BARRICADE_MAX_HEALTH) options.insert_last(2);
if (residents_count > 0 && !blessing_resident_active) options.insert_last(3);
if (!blessing_search_active) options.insert_last(4);
if (options.length() == 0) return;
if (player_health < max_health)
options.insert_last(0);
if (!blessing_speed_active)
options.insert_last(1);
if (barricade_health < BARRICADE_MAX_HEALTH)
options.insert_last(2);
if (residents_count > 0 && !blessing_resident_active)
options.insert_last(3);
if (!blessing_search_active)
options.insert_last(4);
if (options.length() == 0)
return;
int choice = options[random(0, options.length() - 1)];
favor -= 1.0;
if (favor < 0) favor = 0;
if (favor < 0)
favor = 0;
string[] god_names = {
"Odin's", "Thor's", "Freyja's", "Loki's", "Tyr's", "Baldur's",
"Frigg's", "Heimdall's", "Hel's", "Fenrir's", "Freyr's", "The gods'"
};
string[] god_names = {"Odin's", "Thor's", "Freyja's", "Loki's", "Tyr's", "Baldur's",
"Frigg's", "Heimdall's", "Hel's", "Fenrir's", "Freyr's", "The gods'"};
string god_name = god_names[random(0, god_names.length() - 1)];
if (choice == 0) {
int before = player_health;
player_health += BLESSING_HEAL_AMOUNT;
if (player_health > max_health) player_health = max_health;
if (player_health > max_health)
player_health = max_health;
int healed = player_health - before;
string bonus = (healed > 0) ? "You feel restored. +" + healed + " health." : "You feel restored.";
notify(god_name + " favor shines upon you. " + bonus);
@@ -705,8 +766,7 @@ void attempt_blessing() {
notify(god_name + " favor shines upon you. You feel swift for a while.");
} else if (choice == 2) {
int gained = add_barricade_health(BLESSING_BARRICADE_REPAIR);
string bonus = (gained > 0)
? "A divine force repairs the barricade. +" + gained + " health."
string bonus = (gained > 0) ? "A divine force repairs the barricade. +" + gained + " health."
: "A divine force surrounds the barricade.";
notify(god_name + " favor shines upon you. " + bonus);
} else if (choice == 3) {
@@ -722,12 +782,17 @@ void attempt_blessing() {
bool should_attempt_resident_foraging(int hour) {
int residentCount = residents_count;
if (residentCount <= 0) return false;
if (residentCount <= 0)
return false;
if (hour == 6) return true;
if (residentCount == 1) return false;
if (residentCount == 2) return hour == 12;
if (residentCount == 3) return hour == 12 || hour == 18;
if (hour == 6)
return true;
if (residentCount == 1)
return false;
if (residentCount == 2)
return hour == 12;
if (residentCount == 3)
return hour == 12 || hour == 18;
// 4+ residents: spread across daytime hours
return hour == 10 || hour == 14 || hour == 18;
@@ -794,7 +859,8 @@ void update_time() {
if (current_hour >= day_start_hour && current_hour < day_end_hour) {
int repair_window_hours = day_end_hour - day_start_hour;
int interval = repair_window_hours / residents_count;
if (interval < 1) interval = 1;
if (interval < 1)
interval = 1;
int day_hour = current_hour - day_start_hour;
if (day_hour % interval == 0) {
if (has_any_storage_food()) {
@@ -854,7 +920,8 @@ void update_time() {
}
void update_incense_burning() {
if (!incense_burning || incense_hours_remaining <= 0) return;
if (!incense_burning || incense_hours_remaining <= 0)
return;
favor += INCENSE_FAVOR_PER_HOUR;
incense_hours_remaining--;
@@ -964,7 +1031,8 @@ void start_crossfade(bool to_night) {
}
void update_crossfade() {
if (!crossfade_active) return;
if (!crossfade_active)
return;
// If a handle went inactive mid-fade, cancel and restart ambience to avoid fading unrelated sounds.
if (crossfade_to_night) {
@@ -996,7 +1064,8 @@ void update_crossfade() {
}
float progress = float(crossfade_timer.elapsed) / float(CROSSFADE_DURATION);
if (progress > 1.0) progress = 1.0;
if (progress > 1.0)
progress = 1.0;
// Volume interpolation: use a slow-start curve to make fade-outs more gradual
float volume_range = CROSSFADE_MAX_VOLUME - CROSSFADE_MIN_VOLUME; // dB range
@@ -1006,12 +1075,16 @@ void update_crossfade() {
if (crossfade_to_night) {
// Fading day out, night in
if (day_sound_handle != -1) p.update_sound_start_values(day_sound_handle, 0.0, fade_out_vol, 1.0);
if (night_sound_handle != -1) p.update_sound_start_values(night_sound_handle, 0.0, fade_in_vol, 1.0);
if (day_sound_handle != -1)
p.update_sound_start_values(day_sound_handle, 0.0, fade_out_vol, 1.0);
if (night_sound_handle != -1)
p.update_sound_start_values(night_sound_handle, 0.0, fade_in_vol, 1.0);
} else {
// Fading night out, day in
if (night_sound_handle != -1) p.update_sound_start_values(night_sound_handle, 0.0, fade_out_vol, 1.0);
if (day_sound_handle != -1) p.update_sound_start_values(day_sound_handle, 0.0, fade_in_vol, 1.0);
if (night_sound_handle != -1)
p.update_sound_start_values(night_sound_handle, 0.0, fade_out_vol, 1.0);
if (day_sound_handle != -1)
p.update_sound_start_values(day_sound_handle, 0.0, fade_in_vol, 1.0);
}
// Complete the crossfade
@@ -1029,7 +1102,8 @@ void complete_crossfade() {
p.destroy_sound(day_sound_handle);
day_sound_handle = -1;
}
if (night_sound_handle != -1) p.update_sound_start_values(night_sound_handle, 0.0, 0.0, 1.0);
if (night_sound_handle != -1)
p.update_sound_start_values(night_sound_handle, 0.0, 0.0, 1.0);
is_daytime = false;
if (night_sound_handle == -1 || !p.sound_is_active(night_sound_handle)) {
update_ambience(false);
@@ -1040,7 +1114,8 @@ void complete_crossfade() {
p.destroy_sound(night_sound_handle);
night_sound_handle = -1;
}
if (day_sound_handle != -1) p.update_sound_start_values(day_sound_handle, 0.0, 0.0, 1.0);
if (day_sound_handle != -1)
p.update_sound_start_values(day_sound_handle, 0.0, 0.0, 1.0);
is_daytime = true;
if (day_sound_handle == -1 || !p.sound_is_active(day_sound_handle)) {
update_ambience(false);
@@ -1049,7 +1124,8 @@ void complete_crossfade() {
}
void ensure_ambience_running() {
if (crossfade_active) return;
if (crossfade_active)
return;
if (is_daytime) {
if (day_sound_handle == -1 || !p.sound_is_active(day_sound_handle)) {
+21 -13
View File
@@ -3,32 +3,39 @@
funcdef void WeaponRangeAudioCallback();
WeaponRangeAudioCallback@[] weapon_range_audio_callbacks;
WeaponRangeAudioCallback @[] weapon_range_audio_callbacks;
bool weapon_range_audio_initialized = false;
void init_weapon_range_audio_registry() {
if (weapon_range_audio_initialized) return;
if (weapon_range_audio_initialized)
return;
weapon_range_audio_callbacks.resize(0);
weapon_range_audio_initialized = true;
}
bool register_weapon_range_audio_callback(WeaponRangeAudioCallback@ callback) {
bool register_weapon_range_audio_callback(WeaponRangeAudioCallback @callback) {
init_weapon_range_audio_registry();
if (@callback is null) return false;
if (@callback is null)
return false;
weapon_range_audio_callbacks.insert_last(callback);
return true;
}
int get_current_weapon_range() {
if (sling_equipped) return SLING_RANGE;
if (bow_equipped) return BOW_RANGE;
if (spear_equipped) return 1;
if (axe_equipped) return 0;
if (sling_equipped)
return SLING_RANGE;
if (bow_equipped)
return BOW_RANGE;
if (spear_equipped)
return 1;
if (axe_equipped)
return 0;
return -1;
}
void play_weapon_range_sound(string sound_file, int creature_pos) {
if (!file_exists(sound_file)) return;
if (!audio_asset_exists(sound_file))
return;
// Notification sound: keep centered on the player like footsteps
int handle = p.play_stationary(sound_file, false);
if (handle != -1) {
@@ -36,7 +43,7 @@ void play_weapon_range_sound(string sound_file, int creature_pos) {
}
}
void update_weapon_range_audio(int creature_pos, bool &inout was_in_range) {
void update_weapon_range_audio(int creature_pos, bool& inout was_in_range) {
int range = get_current_weapon_range();
bool in_range = (range >= 0) && (abs(creature_pos - x) <= range);
if (in_range && !was_in_range) {
@@ -47,15 +54,16 @@ void update_weapon_range_audio(int creature_pos, bool &inout was_in_range) {
was_in_range = in_range;
}
void force_weapon_range_exit(int creature_pos, bool &inout was_in_range) {
if (!was_in_range) return;
void force_weapon_range_exit(int creature_pos, bool& inout was_in_range) {
if (!was_in_range)
return;
play_weapon_range_sound("sounds/enemies/exit_range.ogg", creature_pos);
was_in_range = false;
}
void update_weapon_range_audio_all() {
for (uint i = 0; i < weapon_range_audio_callbacks.length(); i++) {
WeaponRangeAudioCallback@ callback = weapon_range_audio_callbacks[i];
WeaponRangeAudioCallback @callback = weapon_range_audio_callbacks[i];
if (@callback !is null) {
callback();
}
+44 -33
View File
@@ -47,7 +47,8 @@ class ThunderStrike {
}
void update() {
if (direction == 0) return; // Stationary thunder
if (direction == 0)
return; // Stationary thunder
if (movement_timer.elapsed >= movement_speed) {
position += direction;
@@ -65,23 +66,16 @@ class ThunderStrike {
}
}
ThunderStrike@[] active_thunder;
ThunderStrike @[] active_thunder;
timer thunder_timer;
int next_thunder_interval = 0;
// Sound file paths
string[] wind_sounds = {
"", // INTENSITY_NONE placeholder
"sounds/nature/wind_low.ogg",
"sounds/nature/wind_medium.ogg",
"sounds/nature/wind_high.ogg"
};
string[] wind_sounds = {"", // INTENSITY_NONE placeholder
"sounds/nature/wind_low.ogg", "sounds/nature/wind_medium.ogg", "sounds/nature/wind_high.ogg"};
string[] thunder_sounds = {
"sounds/nature/thunder_low.ogg",
"sounds/nature/thunder_medium.ogg",
"sounds/nature/thunder_high.ogg"
};
string[] thunder_sounds = {"sounds/nature/thunder_low.ogg", "sounds/nature/thunder_medium.ogg",
"sounds/nature/thunder_high.ogg"};
void init_weather() {
stop_all_weather_sounds();
@@ -236,8 +230,10 @@ void maybe_change_wind_intensity() {
if (random(1, 100) <= 30) {
int change = random(-1, 1);
int new_intensity = wind_intensity + change;
if (new_intensity < INTENSITY_LOW) new_intensity = INTENSITY_LOW;
if (new_intensity > INTENSITY_HIGH) new_intensity = INTENSITY_HIGH;
if (new_intensity < INTENSITY_LOW)
new_intensity = INTENSITY_LOW;
if (new_intensity > INTENSITY_HIGH)
new_intensity = INTENSITY_HIGH;
wind_intensity = new_intensity;
}
}
@@ -246,8 +242,10 @@ void maybe_change_rain_intensity() {
if (random(1, 100) <= 30) {
int change = random(-1, 1);
int new_intensity = rain_intensity + change;
if (new_intensity < INTENSITY_LOW) new_intensity = INTENSITY_LOW;
if (new_intensity > INTENSITY_HIGH) new_intensity = INTENSITY_HIGH;
if (new_intensity < INTENSITY_LOW)
new_intensity = INTENSITY_LOW;
if (new_intensity > INTENSITY_HIGH)
new_intensity = INTENSITY_HIGH;
if (new_intensity != rain_intensity) {
fade_rain_to_intensity(new_intensity);
}
@@ -258,15 +256,19 @@ void maybe_change_storm_intensity() {
// Possibly change wind
if (random(1, 100) <= 25) {
int new_wind = wind_intensity + random(-1, 1);
if (new_wind < INTENSITY_LOW) new_wind = INTENSITY_LOW;
if (new_wind > INTENSITY_HIGH) new_wind = INTENSITY_HIGH;
if (new_wind < INTENSITY_LOW)
new_wind = INTENSITY_LOW;
if (new_wind > INTENSITY_HIGH)
new_wind = INTENSITY_HIGH;
wind_intensity = new_wind;
}
// Possibly change rain
if (random(1, 100) <= 25) {
int new_rain = rain_intensity + random(-1, 1);
if (new_rain < INTENSITY_LOW) new_rain = INTENSITY_LOW;
if (new_rain > INTENSITY_HIGH) new_rain = INTENSITY_HIGH;
if (new_rain < INTENSITY_LOW)
new_rain = INTENSITY_LOW;
if (new_rain > INTENSITY_HIGH)
new_rain = INTENSITY_HIGH;
if (new_rain != rain_intensity) {
fade_rain_to_intensity(new_rain);
}
@@ -275,7 +277,8 @@ void maybe_change_storm_intensity() {
// Wind gust implementation
void update_wind_gusts() {
if (wind_intensity == INTENSITY_NONE) return;
if (wind_intensity == INTENSITY_NONE)
return;
// Check if it's time for next gust
if (wind_gust_timer.elapsed >= next_wind_gust_delay) {
@@ -286,7 +289,8 @@ void update_wind_gusts() {
}
void play_wind_gust() {
if (wind_intensity == INTENSITY_NONE || wind_intensity > INTENSITY_HIGH) return;
if (wind_intensity == INTENSITY_NONE || wind_intensity > INTENSITY_HIGH)
return;
// Clean up previous wind gust if it's stale
if (wind_sound_handle != -1 && !p.sound_is_active(wind_sound_handle)) {
@@ -300,14 +304,18 @@ void play_wind_gust() {
// Rain fade implementation
float get_rain_target_volume(int intensity) {
if (intensity == INTENSITY_NONE) return WEATHER_MIN_VOLUME;
if (intensity == INTENSITY_LOW) return RAIN_VOLUME_LIGHT;
if (intensity == INTENSITY_MEDIUM) return RAIN_VOLUME_MODERATE;
if (intensity == INTENSITY_NONE)
return WEATHER_MIN_VOLUME;
if (intensity == INTENSITY_LOW)
return RAIN_VOLUME_LIGHT;
if (intensity == INTENSITY_MEDIUM)
return RAIN_VOLUME_MODERATE;
return RAIN_VOLUME_HEAVY;
}
void fade_rain_to_intensity(int new_intensity) {
if (new_intensity == rain_intensity && !rain_fading) return;
if (new_intensity == rain_intensity && !rain_fading)
return;
// Complete any current fade
if (rain_fading) {
@@ -341,14 +349,16 @@ void fade_rain_to_intensity(int new_intensity) {
}
void update_rain_fade() {
if (!rain_fading) return;
if (!rain_fading)
return;
if (rain_sound_handle == -1) {
rain_fading = false;
return;
}
float progress = float(rain_fade_timer.elapsed) / float(rain_fade_duration);
if (progress > 1.0) progress = 1.0;
if (progress > 1.0)
progress = 1.0;
float current_vol = rain_fade_from_volume + ((rain_fade_to_volume - rain_fade_from_volume) * progress);
p.update_sound_start_values(rain_sound_handle, 0.0, current_vol, 1.0);
@@ -384,7 +394,8 @@ void update_thunder() {
}
}
if (!thunder_enabled) return;
if (!thunder_enabled)
return;
// Check if it's time for new thunder
if (thunder_timer.elapsed >= next_thunder_interval) {
@@ -417,7 +428,7 @@ void spawn_thunder() {
int handle = play_1d_with_volume_step(thunder_file, x, thunder_pos, false, THUNDER_SOUND_VOLUME_STEP);
if (handle != -1) {
ThunderStrike@ strike = ThunderStrike(thunder_pos, direction, handle, speed);
ThunderStrike @strike = ThunderStrike(thunder_pos, direction, handle, speed);
active_thunder.insert_last(strike);
}
} else {
@@ -429,7 +440,7 @@ void spawn_thunder() {
int handle = play_1d_with_volume_step(thunder_file, x, thunder_pos, false, THUNDER_SOUND_VOLUME_STEP);
if (handle != -1) {
ThunderStrike@ strike = ThunderStrike(thunder_pos, 0, handle, 0);
ThunderStrike @strike = ThunderStrike(thunder_pos, 0, handle, 0);
active_thunder.insert_last(strike);
}
}
@@ -462,7 +473,7 @@ string serialize_weather() {
}
void deserialize_weather(string data) {
string[]@ parts = data.split("|");
string[] @parts = data.split("|");
if (parts.length() < 4) {
init_weather();
return;
+52 -34
View File
@@ -32,8 +32,10 @@ class MountainRange {
// Clamp values to valid range
for (int i = 0; i < size; i++) {
if (elevations[i] < MOUNTAIN_MIN_ELEVATION) elevations[i] = MOUNTAIN_MIN_ELEVATION;
if (elevations[i] > MOUNTAIN_MAX_ELEVATION) elevations[i] = MOUNTAIN_MAX_ELEVATION;
if (elevations[i] < MOUNTAIN_MIN_ELEVATION)
elevations[i] = MOUNTAIN_MIN_ELEVATION;
if (elevations[i] > MOUNTAIN_MAX_ELEVATION)
elevations[i] = MOUNTAIN_MAX_ELEVATION;
}
// Smooth to enforce max slope constraint
@@ -63,7 +65,8 @@ class MountainRange {
}
void midpoint_displace(int left, int right, int roughness) {
if (right - left <= 1) return;
if (right - left <= 1)
return;
int mid = (left + right) / 2;
int avg = (elevations[left] + elevations[right]) / 2;
@@ -71,7 +74,8 @@ class MountainRange {
elevations[mid] = avg + displacement;
int new_roughness = roughness * 7 / 10;
if (new_roughness < 1) new_roughness = 1;
if (new_roughness < 1)
new_roughness = 1;
midpoint_displace(left, mid, new_roughness);
midpoint_displace(mid, right, new_roughness);
@@ -85,12 +89,12 @@ class MountainRange {
iterations++;
for (int i = 1; i < int(elevations.length()); i++) {
int diff = elevations[i] - elevations[i-1];
int diff = elevations[i] - elevations[i - 1];
if (diff > MOUNTAIN_MAX_SLOPE) {
elevations[i] = elevations[i-1] + MOUNTAIN_MAX_SLOPE;
elevations[i] = elevations[i - 1] + MOUNTAIN_MAX_SLOPE;
changed = true;
} else if (diff < -MOUNTAIN_MAX_SLOPE) {
elevations[i] = elevations[i-1] - MOUNTAIN_MAX_SLOPE;
elevations[i] = elevations[i - 1] - MOUNTAIN_MAX_SLOPE;
changed = true;
}
}
@@ -105,7 +109,7 @@ class MountainRange {
// Find all steep sections (positions where rope would be needed)
int[] steep_positions;
for (int i = 1; i < size; i++) {
if (abs(elevations[i] - elevations[i-1]) >= MOUNTAIN_STEEP_THRESHOLD) {
if (abs(elevations[i] - elevations[i - 1]) >= MOUNTAIN_STEEP_THRESHOLD) {
steep_positions.insert_last(i);
}
}
@@ -115,7 +119,8 @@ class MountainRange {
int steep_pos = steep_positions[s];
// Check if we have enough tiles after this steep section for a plateau
if (steep_pos + MIN_PLATEAU_TILES >= size) continue;
if (steep_pos + MIN_PLATEAU_TILES >= size)
continue;
// Get the elevation after the steep climb
int plateau_start_elevation = elevations[steep_pos];
@@ -123,7 +128,8 @@ class MountainRange {
// Ensure next MIN_PLATEAU_TILES have gentle slopes
for (int p = 1; p <= MIN_PLATEAU_TILES; p++) {
int tile_idx = steep_pos + p;
if (tile_idx >= size) break;
if (tile_idx >= size)
break;
// Calculate max allowed elevation change for gentle slope
int prev_elevation = elevations[tile_idx - 1];
@@ -146,7 +152,8 @@ class MountainRange {
// Final pass: ensure no negative elevations anywhere
for (int i = 0; i < size; i++) {
if (elevations[i] < 0) elevations[i] = 0;
if (elevations[i] < 0)
elevations[i] = 0;
}
// Prefer climbing up before descending by adjusting early terrain
@@ -170,15 +177,19 @@ class MountainRange {
// Find valley bottoms (local minima)
int[] valleys;
for (int i = 2; i < int(elevations.length()) - 2; i++) {
if (elevations[i] < elevations[i-1] && elevations[i] < elevations[i+1] &&
elevations[i] < elevations[i-2] && elevations[i] < elevations[i+2]) {
if (elevations[i] < elevations[i - 1] && elevations[i] < elevations[i + 1] &&
elevations[i] < elevations[i - 2] && elevations[i] < elevations[i + 2]) {
// Keep mountain streams off both extreme edge tiles.
if (i > 0 && i < int(elevations.length()) - 1) {
valleys.insert_last(i);
}
}
}
// Place 1-3 streams in valleys
int num_streams = random(1, 3);
if (num_streams > int(valleys.length())) num_streams = int(valleys.length());
if (num_streams > int(valleys.length()))
num_streams = int(valleys.length());
for (int i = 0; i < num_streams && valleys.length() > 0; i++) {
int idx = random(0, int(valleys.length()) - 1);
@@ -193,12 +204,12 @@ class MountainRange {
// Check if we already have a steep climb (≥7) to/from 10-20 elevation
bool has_steep_climb = false;
for (int i = 1; i < size; i++) {
int diff = abs(elevations[i] - elevations[i-1]);
int diff = abs(elevations[i] - elevations[i - 1]);
if (diff >= MOUNTAIN_STEEP_THRESHOLD) {
// Check if either elevation is in 10-20 range
if ((elevations[i] >= 10 && elevations[i] <= 20) ||
(elevations[i-1] >= 10 && elevations[i-1] <= 20)) {
(elevations[i - 1] >= 10 && elevations[i - 1] <= 20)) {
has_steep_climb = true;
break;
}
@@ -248,24 +259,26 @@ class MountainRange {
// Last transition: tile size-2 to tile size-1
if (size >= 2) {
if (abs(elevations[size-1] - elevations[size-2]) > 20) {
if (elevations[size-2] > elevations[size-1]) {
elevations[size-2] = elevations[size-1] + 20;
if (abs(elevations[size - 1] - elevations[size - 2]) > 20) {
if (elevations[size - 2] > elevations[size - 1]) {
elevations[size - 2] = elevations[size - 1] + 20;
} else {
elevations[size-2] = elevations[size-1] - 20;
elevations[size - 2] = elevations[size - 1] - 20;
}
}
}
}
int get_elevation_at(int world_x) {
if (world_x < start_position || world_x > end_position) return 0;
if (world_x < start_position || world_x > end_position)
return 0;
int index = world_x - start_position;
return elevations[index];
}
string get_terrain_at(int world_x) {
if (world_x < start_position || world_x > end_position) return "stone";
if (world_x < start_position || world_x > end_position)
return "stone";
int index = world_x - start_position;
return terrain_types[index];
}
@@ -285,16 +298,19 @@ class MountainRange {
}
bool is_stream_at(int world_x) {
if (!contains_position(world_x)) return false;
if (!contains_position(world_x))
return false;
int index = world_x - start_position;
for (uint i = 0; i < stream_positions.length(); i++) {
if (stream_positions[i] == index) return true;
if (stream_positions[i] == index)
return true;
}
return false;
}
void update() {
if (stream_positions.length() == 0) return;
if (stream_positions.length() == 0)
return;
// Find nearest stream to player
int nearest_stream = -1;
@@ -336,10 +352,9 @@ class MountainRange {
}
stream_sound_position = -1;
}
}
MountainRange@[] world_mountains;
} MountainRange @[] world_mountains;
MountainRange@ get_mountain_at(int world_x) {
MountainRange @get_mountain_at(int world_x) {
for (uint i = 0; i < world_mountains.length(); i++) {
if (world_mountains[i].contains_position(world_x)) {
return @world_mountains[i];
@@ -349,21 +364,24 @@ MountainRange@ get_mountain_at(int world_x) {
}
int get_mountain_elevation_at(int world_x) {
MountainRange@ mountain = get_mountain_at(world_x);
if (mountain is null) return 0;
MountainRange @mountain = get_mountain_at(world_x);
if (mountain is null)
return 0;
return mountain.get_elevation_at(world_x);
}
bool is_mountain_stream_at(int world_x) {
MountainRange@ mountain = get_mountain_at(world_x);
if (mountain is null) return false;
MountainRange @mountain = get_mountain_at(world_x);
if (mountain is null)
return false;
return mountain.is_stream_at(world_x);
}
void update_mountains_with_audio_areas(int[]@ areaStarts, int[]@ areaEnds) {
void update_mountains_with_audio_areas(int[] @areaStarts, int[] @areaEnds) {
bool limit_audio = (areaStarts.length() > 0);
for (uint i = 0; i < world_mountains.length(); i++) {
if (limit_audio && !range_overlaps_active_areas(world_mountains[i].start_position, world_mountains[i].end_position, areaStarts, areaEnds)) {
if (limit_audio && !range_overlaps_active_areas(world_mountains[i].start_position,
world_mountains[i].end_position, areaStarts, areaEnds)) {
world_mountains[i].destroy();
continue;
}
+21 -27
View File
@@ -7,8 +7,7 @@ class WorldFirepit {
WorldFirepit(int pos) {
position = pos;
}
}
WorldFirepit@[] world_firepits;
} WorldFirepit @[] world_firepits;
class WorldHerbGarden {
int position;
@@ -16,8 +15,7 @@ class WorldHerbGarden {
WorldHerbGarden(int pos) {
position = pos;
}
}
WorldHerbGarden@[] world_herb_gardens;
} WorldHerbGarden @[] world_herb_gardens;
class WorldStorage {
int position;
@@ -25,8 +23,7 @@ class WorldStorage {
WorldStorage(int pos) {
position = pos;
}
}
WorldStorage@[] world_storages;
} WorldStorage @[] world_storages;
class WorldPasture {
int position;
@@ -34,8 +31,7 @@ class WorldPasture {
WorldPasture(int pos) {
position = pos;
}
}
WorldPasture@[] world_pastures;
} WorldPasture @[] world_pastures;
class WorldStable {
int position;
@@ -43,8 +39,7 @@ class WorldStable {
WorldStable(int pos) {
position = pos;
}
}
WorldStable@[] world_stables;
} WorldStable @[] world_stables;
class WorldAltar {
int position;
@@ -52,8 +47,7 @@ class WorldAltar {
WorldAltar(int pos) {
position = pos;
}
}
WorldAltar@[] world_altars;
} WorldAltar @[] world_altars;
int horses_count = 0;
int livestock_count = 0;
@@ -61,17 +55,17 @@ int storage_level = STORAGE_LEVEL_BASE;
// Add functions
void add_world_firepit(int pos) {
WorldFirepit@ fp = WorldFirepit(pos);
WorldFirepit @fp = WorldFirepit(pos);
world_firepits.insert_last(fp);
}
void add_world_herb_garden(int pos) {
WorldHerbGarden@ hg = WorldHerbGarden(pos);
WorldHerbGarden @hg = WorldHerbGarden(pos);
world_herb_gardens.insert_last(hg);
}
void add_world_storage(int pos) {
WorldStorage@ s = WorldStorage(pos);
WorldStorage @s = WorldStorage(pos);
world_storages.insert_last(s);
}
@@ -82,22 +76,22 @@ void ensure_base_storage() {
}
void add_world_pasture(int pos) {
WorldPasture@ p = WorldPasture(pos);
WorldPasture @p = WorldPasture(pos);
world_pastures.insert_last(p);
}
void add_world_stable(int pos) {
WorldStable@ s = WorldStable(pos);
WorldStable @s = WorldStable(pos);
world_stables.insert_last(s);
}
void add_world_altar(int pos) {
WorldAltar@ a = WorldAltar(pos);
WorldAltar @a = WorldAltar(pos);
world_altars.insert_last(a);
}
// Getter functions
WorldFirepit@ get_firepit_at(int pos) {
WorldFirepit @get_firepit_at(int pos) {
for (uint i = 0; i < world_firepits.length(); i++) {
if (world_firepits[i].position == pos) {
return @world_firepits[i];
@@ -106,10 +100,10 @@ WorldFirepit@ get_firepit_at(int pos) {
return null;
}
WorldFirepit@ get_firepit_near(int pos, int range) {
WorldFirepit @get_firepit_near(int pos, int range) {
// Check for firepit within specified range
for (int check_x = pos - range; check_x <= pos + range; check_x++) {
WorldFirepit@ firepit = get_firepit_at(check_x);
WorldFirepit @firepit = get_firepit_at(check_x);
if (firepit != null) {
return @firepit;
}
@@ -117,7 +111,7 @@ WorldFirepit@ get_firepit_near(int pos, int range) {
return null;
}
WorldHerbGarden@ get_herb_garden_at(int pos) {
WorldHerbGarden @get_herb_garden_at(int pos) {
for (uint i = 0; i < world_herb_gardens.length(); i++) {
if (world_herb_gardens[i].position == pos) {
return @world_herb_gardens[i];
@@ -126,7 +120,7 @@ WorldHerbGarden@ get_herb_garden_at(int pos) {
return null;
}
WorldHerbGarden@ get_herb_garden_at_base() {
WorldHerbGarden @get_herb_garden_at_base() {
// Check if herb garden exists anywhere in base area (0-4)
for (uint i = 0; i < world_herb_gardens.length(); i++) {
if (world_herb_gardens[i].position <= BASE_END) {
@@ -136,7 +130,7 @@ WorldHerbGarden@ get_herb_garden_at_base() {
return null;
}
WorldStorage@ get_storage_at(int pos) {
WorldStorage @get_storage_at(int pos) {
for (uint i = 0; i < world_storages.length(); i++) {
if (world_storages[i].position == pos) {
return @world_storages[i];
@@ -145,7 +139,7 @@ WorldStorage@ get_storage_at(int pos) {
return null;
}
WorldPasture@ get_pasture_at(int pos) {
WorldPasture @get_pasture_at(int pos) {
for (uint i = 0; i < world_pastures.length(); i++) {
if (world_pastures[i].position == pos) {
return @world_pastures[i];
@@ -154,7 +148,7 @@ WorldPasture@ get_pasture_at(int pos) {
return null;
}
WorldStable@ get_stable_at(int pos) {
WorldStable @get_stable_at(int pos) {
for (uint i = 0; i < world_stables.length(); i++) {
if (world_stables[i].position == pos) {
return @world_stables[i];
@@ -163,7 +157,7 @@ WorldStable@ get_stable_at(int pos) {
return null;
}
WorldAltar@ get_altar_at(int pos) {
WorldAltar @get_altar_at(int pos) {
for (uint i = 0; i < world_altars.length(); i++) {
if (world_altars[i].position == pos) {
return @world_altars[i];
+6 -6
View File
@@ -40,11 +40,10 @@ class WorldDrop {
sound_handle = -1;
}
}
}
WorldDrop@[] world_drops;
} WorldDrop @[] world_drops;
void add_world_drop(int pos, string type) {
WorldDrop@ d = WorldDrop(pos, type);
WorldDrop @d = WorldDrop(pos, type);
world_drops.insert_last(d);
}
@@ -55,7 +54,8 @@ void update_world_drops() {
bool limit_audio = (areaStarts.length() > 0);
for (uint i = 0; i < world_drops.length(); i++) {
if (limit_audio && !range_overlaps_active_areas(world_drops[i].position, world_drops[i].position, areaStarts, areaEnds)) {
if (limit_audio &&
!range_overlaps_active_areas(world_drops[i].position, world_drops[i].position, areaStarts, areaEnds)) {
world_drops[i].destroy();
continue;
}
@@ -63,7 +63,7 @@ void update_world_drops() {
}
}
WorldDrop@ get_drop_at(int pos) {
WorldDrop @get_drop_at(int pos) {
for (uint i = 0; i < world_drops.length(); i++) {
if (world_drops[i].position == pos) {
return @world_drops[i];
@@ -100,7 +100,7 @@ bool try_pickup_small_game(string game_type) {
return true;
}
bool try_pickup_world_drop(WorldDrop@ drop) {
bool try_pickup_world_drop(WorldDrop @drop) {
if (get_flying_creature_config_by_drop_type(drop.type) !is null) {
return try_pickup_small_game(drop.type);
}
+9 -9
View File
@@ -78,11 +78,10 @@ class WorldFire {
sound_handle = -1;
}
}
}
WorldFire@[] world_fires;
} WorldFire @[] world_fires;
void add_world_fire(int pos) {
WorldFire@ f = WorldFire(pos);
WorldFire @f = WorldFire(pos);
world_fires.insert_last(f);
}
@@ -95,7 +94,8 @@ void update_fires() {
// Update all fires and remove any that have burned out
for (uint i = 0; i < world_fires.length(); i++) {
world_fires[i].update();
if (limit_audio && !range_overlaps_active_areas(world_fires[i].position, world_fires[i].position, areaStarts, areaEnds)) {
if (limit_audio &&
!range_overlaps_active_areas(world_fires[i].position, world_fires[i].position, areaStarts, areaEnds)) {
if (world_fires[i].sound_handle != -1) {
p.destroy_sound(world_fires[i].sound_handle);
world_fires[i].sound_handle = -1;
@@ -113,7 +113,7 @@ void update_fires() {
}
}
WorldFire@ get_fire_at(int pos) {
WorldFire @get_fire_at(int pos) {
for (uint i = 0; i < world_fires.length(); i++) {
if (world_fires[i].position == pos) {
return @world_fires[i];
@@ -122,10 +122,10 @@ WorldFire@ get_fire_at(int pos) {
return null;
}
WorldFire@ get_fire_near(int pos) {
WorldFire @get_fire_near(int pos) {
// Check for fire at current position or adjacent tiles
for (int check_x = pos - 1; check_x <= pos + 1; check_x++) {
WorldFire@ fire = get_fire_at(check_x);
WorldFire @fire = get_fire_at(check_x);
if (fire != null && fire.is_burning()) {
return @fire;
}
@@ -133,10 +133,10 @@ WorldFire@ get_fire_near(int pos) {
return null;
}
WorldFire@ get_fire_within_range(int pos, int range) {
WorldFire @get_fire_within_range(int pos, int range) {
// Check for fire within specified range
for (int check_x = pos - range; check_x <= pos + range; check_x++) {
WorldFire@ fire = get_fire_at(check_x);
WorldFire @fire = get_fire_at(check_x);
if (fire != null && fire.is_burning()) {
return @fire;
}
+11 -9
View File
@@ -51,7 +51,8 @@ class WorldSnare {
}
sound_handle = p.play_1d("sounds/actions/set_snare.ogg", x, position, true);
if (sound_handle != -1) {
p.update_sound_positioning_values(sound_handle, SNARE_SOUND_PAN_STEP, SNARE_SOUND_VOLUME_STEP, true);
p.update_sound_positioning_values(sound_handle, SNARE_SOUND_PAN_STEP, SNARE_SOUND_VOLUME_STEP,
true);
}
}
} else if (sound_handle != -1) {
@@ -71,7 +72,8 @@ class WorldSnare {
// After that: escape chance increases by 2% per game hour
if (hours_with_catch > 1) {
escape_chance = (hours_with_catch - 1) * 2;
if (escape_chance > 95) escape_chance = 95;
if (escape_chance > 95)
escape_chance = 95;
int roll = random(1, 100);
if (roll <= escape_chance) {
@@ -83,7 +85,8 @@ class WorldSnare {
}
} else {
// Trying to catch small game
if (catch_chance < 75) catch_chance += 5;
if (catch_chance < 75)
catch_chance += 5;
int roll = random(1, 100);
if (roll <= catch_chance) {
@@ -104,15 +107,14 @@ class WorldSnare {
sound_handle = -1;
}
}
}
WorldSnare@[] world_snares;
} WorldSnare @[] world_snares;
void add_world_snare(int pos) {
WorldSnare@ s = WorldSnare(pos);
WorldSnare @s = WorldSnare(pos);
world_snares.insert_last(s);
}
WorldSnare@ get_snare_at(int pos) {
WorldSnare @get_snare_at(int pos) {
for (uint i = 0; i < world_snares.length(); i++) {
if (world_snares[i].position == pos) {
return @world_snares[i];
@@ -133,7 +135,7 @@ void remove_snare_at(int pos) {
// Called when player moves onto a tile
void check_snare_collision(int player_x) {
WorldSnare@ s = get_snare_at(player_x);
WorldSnare @s = get_snare_at(player_x);
if (s != null && s.active) {
// Break the snare
p.play_stationary("sounds/actions/break_snare.ogg", false);
@@ -155,7 +157,7 @@ void update_snares() {
bool limit_audio = (areaStarts.length() > 0);
for (int i = int(world_snares.length()) - 1; i >= 0; i--) {
WorldSnare@ snare = world_snares[i];
WorldSnare @snare = world_snares[i];
snare.update();
if (limit_audio && !range_overlaps_active_areas(snare.position, snare.position, areaStarts, areaEnds)) {
if (snare.sound_handle != -1) {
+19 -14
View File
@@ -63,8 +63,7 @@ class WorldStream {
}
sound_position = -1;
}
}
WorldStream@[] world_streams;
} WorldStream @[] world_streams;
string get_expanded_area_type(int index) {
string terrain = expanded_terrain_types[index];
@@ -74,7 +73,7 @@ string get_expanded_area_type(int index) {
return terrain;
}
bool get_audio_area_bounds_for_position(int pos, int &out areaStart, int &out areaEnd) {
bool get_audio_area_bounds_for_position(int pos, int& out areaStart, int& out areaEnd) {
if (pos <= BASE_END) {
areaStart = 0;
areaEnd = BASE_END;
@@ -97,18 +96,21 @@ bool get_audio_area_bounds_for_position(int pos, int &out areaStart, int &out ar
int index = pos - expanded_area_start;
int total = int(expanded_terrain_types.length());
if (index < 0 || index >= total) return false;
if (index < 0 || index >= total)
return false;
string areaType = get_expanded_area_type(index);
int left = index;
while (left > 0) {
if (get_expanded_area_type(left - 1) != areaType) break;
if (get_expanded_area_type(left - 1) != areaType)
break;
left--;
}
int right = index;
while (right + 1 < total) {
if (get_expanded_area_type(right + 1) != areaType) break;
if (get_expanded_area_type(right + 1) != areaType)
break;
right++;
}
@@ -117,13 +119,14 @@ bool get_audio_area_bounds_for_position(int pos, int &out areaStart, int &out ar
return true;
}
void get_active_audio_areas(int[]@ areaStarts, int[]@ areaEnds) {
void get_active_audio_areas(int[] @areaStarts, int[] @areaEnds) {
areaStarts.resize(0);
areaEnds.resize(0);
int currentStart = 0;
int currentEnd = 0;
if (!get_audio_area_bounds_for_position(x, currentStart, currentEnd)) return;
if (!get_audio_area_bounds_for_position(x, currentStart, currentEnd))
return;
areaStarts.insert_last(currentStart);
areaEnds.insert_last(currentEnd);
@@ -151,7 +154,7 @@ void get_active_audio_areas(int[]@ areaStarts, int[]@ areaEnds) {
}
}
bool range_overlaps_active_areas(int rangeStart, int rangeEnd, int[]@ areaStarts, int[]@ areaEnds) {
bool range_overlaps_active_areas(int rangeStart, int rangeEnd, int[] @areaStarts, int[] @areaEnds) {
for (uint i = 0; i < areaStarts.length(); i++) {
if (rangeEnd >= areaStarts[i] && rangeStart <= areaEnds[i]) {
return true;
@@ -161,7 +164,7 @@ bool range_overlaps_active_areas(int rangeStart, int rangeEnd, int[]@ areaStarts
}
void add_world_stream(int start_pos, int width) {
WorldStream@ s = WorldStream(start_pos, width);
WorldStream @s = WorldStream(start_pos, width);
world_streams.insert_last(s);
}
@@ -172,7 +175,8 @@ void update_streams() {
bool limit_audio = areaStarts.length() > 0;
for (uint i = 0; i < world_streams.length(); i++) {
if (limit_audio && !range_overlaps_active_areas(world_streams[i].start_position, world_streams[i].end_position, areaStarts, areaEnds)) {
if (limit_audio && !range_overlaps_active_areas(world_streams[i].start_position, world_streams[i].end_position,
areaStarts, areaEnds)) {
world_streams[i].destroy();
continue;
}
@@ -182,7 +186,7 @@ void update_streams() {
update_mountains_with_audio_areas(areaStarts, areaEnds);
}
WorldStream@ get_stream_at(int pos) {
WorldStream @get_stream_at(int pos) {
for (uint i = 0; i < world_streams.length(); i++) {
if (world_streams[i].contains_position(pos)) {
return @world_streams[i];
@@ -196,7 +200,8 @@ bool is_position_in_water(int pos) {
}
bool is_deep_stream_at(int pos) {
WorldStream@ stream = get_stream_at(pos);
if (stream == null) return false;
WorldStream @stream = get_stream_at(pos);
if (stream == null)
return false;
return stream.get_width() > 3;
}