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);
}
}
+244 -147
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,9 +1070,8 @@ void attempt_resident_foraging() {
if (baskets_broken > 0) {
add_storage_count(ITEM_REED_BASKETS, -baskets_broken);
if (x <= BASE_END) {
string msg = (baskets_broken == 1)
? "A resident's basket broke while foraging."
: baskets_broken + " baskets broke while foraging.";
string msg = (baskets_broken == 1) ? "A resident's basket broke while foraging."
: baskets_broken + " baskets broke while foraging.";
speak_with_history(msg, true);
}
}
+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);
}
+14 -12
View File
@@ -23,12 +23,12 @@ void run_adventure_menu(int player_x) {
}
string terrain = get_terrain_at_position(player_x);
MountainRange@ mountain = get_mountain_at(player_x);
MountainRange @mountain = get_mountain_at(player_x);
// Check available adventures based on terrain
string[] options;
int[] adventure_ids; // 1 = Unicorn, 2 = Bandit's Hideout
if (mountain !is null) {
// Mountain terrain
options.insert_last("Unicorn Hunt (Mountain Boss)");
@@ -39,40 +39,42 @@ void run_adventure_menu(int player_x) {
options.insert_last("Bandit's Hideout");
adventure_ids.insert_last(ADVENTURE_BANDIT_HIDEOUT);
}
if (options.length() == 0) {
speak_with_history("No adventures found in this area.", true);
return;
}
// Show Menu
speak_with_history("Adventure Menu.", true);
int selection = 0;
speak_with_history(options[selection], true);
while (true) {
wait(5);
handle_global_volume_keys();
if (key_pressed(KEY_ESCAPE)) {
speak_with_history("Closed.", true);
return;
}
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= options.length()) selection = 0;
if (selection >= options.length())
selection = 0;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = options.length() - 1;
if (selection < 0)
selection = options.length() - 1;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
play_menu_select_sound();
start_adventure(adventure_ids[selection]);
+131 -69
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 {
+67 -39
View File
@@ -10,11 +10,11 @@ class UnicornBoss {
timer move_timer;
int sound_handle;
bool on_bridge;
UnicornBoss() {
reset();
}
void reset() {
health = 450;
speed = UNICORN_SPEED;
@@ -32,7 +32,7 @@ const int BRIDGE_START = 45;
const int BRIDGE_END = 54;
const int BRIDGE_SUPPORT_MAX_HEALTH = 100;
const float UNICORN_SOUND_VOLUME_STEP = 2.5; // Lower = audible from further away
const int UNICORN_SPEED = 80; // ms per tile, 100 tiles * 80ms = 8 seconds per charge
const int UNICORN_SPEED = 80; // ms per tile, 100 tiles * 80ms = 8 seconds per charge
const bool UNICORN_BOW_CAN_DAMAGE_SUPPORTS = false;
const bool UNICORN_SLING_CAN_DAMAGE_SUPPORTS = false;
@@ -44,7 +44,7 @@ bool player_arena_jumping = false;
timer arena_jump_timer;
timer arena_walk_timer;
timer arena_attack_timer;
int player_arena_facing = 1; // 0 = west, 1 = east
int player_arena_facing = 1; // 0 = west, 1 = east
int[] bridge_supports_health; // 2 supports: Left (start) and Right (end)
bool bridge_collapsed = false;
string current_unicorn_sound = "";
@@ -168,13 +168,15 @@ void run_unicorn_adventure() {
// Coordinates
if (key_pressed(KEY_X)) {
string facing_dir = (unicorn.facing == 1) ? "east" : "west";
string terrain = (player_arena_x >= BRIDGE_START && player_arena_x <= BRIDGE_END && !bridge_collapsed) ? "wood" : "grass";
string terrain = (player_arena_x >= BRIDGE_START && player_arena_x <= BRIDGE_END && !bridge_collapsed)
? "wood"
: "grass";
speak_with_history("x " + player_arena_x + ", terrain " + terrain + ". Unicorn facing " + facing_dir, true);
}
handle_player_movement();
handle_player_actions();
// Updates
update_player_jump();
update_unicorn();
@@ -182,7 +184,7 @@ void run_unicorn_adventure() {
update_unicorn_weapon_range_audio();
update_pet_adventure_position(player_arena_x);
update_pets();
// Check Conditions - unicorn falls when on collapsed bridge
if (!unicorn_defeated && bridge_collapsed && unicorn.x >= BRIDGE_START && unicorn.x <= BRIDGE_END) {
mark_unicorn_defeated(true);
@@ -202,14 +204,14 @@ void run_unicorn_adventure() {
give_unicorn_rewards();
return;
}
if (player_health <= 0) {
cleanup_unicorn_adventure();
speak_with_history("The Unicorn trampled you.", true);
// Player death will be handled by main game loop checking player_health <= 0
return;
return;
}
// Audio
p.update_listener_1d(player_arena_x);
update_unicorn_audio();
@@ -236,13 +238,15 @@ void handle_player_movement() {
player_arena_x--;
arena_walk_timer.restart();
check_player_chasm_fall();
if (player_health > 0) play_footstep_sound();
if (player_health > 0)
play_footstep_sound();
} else if (key_down(KEY_RIGHT) && player_arena_x < UNICORN_ARENA_SIZE - 1) {
player_arena_facing = 1;
player_arena_x++;
arena_walk_timer.restart();
check_player_chasm_fall();
if (player_health > 0) play_footstep_sound();
if (player_health > 0)
play_footstep_sound();
}
}
@@ -283,8 +287,10 @@ void check_player_chasm_fall() {
float height_remaining = float(total_fall - feet_fallen);
float pitch_percent = 50.0 + (50.0 * (height_remaining / float(total_fall)));
if (pitch_percent < 50.0) pitch_percent = 50.0;
if (pitch_percent > 100.0) pitch_percent = 100.0;
if (pitch_percent < 50.0)
pitch_percent = 50.0;
if (pitch_percent > 100.0)
pitch_percent = 100.0;
fall_handle = p.play_stationary_extended("sounds/actions/falling.ogg", true, 0, 0, 0, pitch_percent);
}
@@ -309,7 +315,8 @@ void update_player_jump() {
void handle_player_actions() {
// Can't attack while jumping
if (player_arena_jumping) return;
if (player_arena_jumping)
return;
bool ctrl_down = (key_down(KEY_LCTRL) || key_down(KEY_RCTRL));
@@ -360,14 +367,18 @@ void handle_player_actions() {
// Non-sling weapon attacks (existing pattern)
if (!bow_equipped && !bow_drawing && !sling_equipped && !sling_charging) {
if (fishing_pole_equipped) return;
if (fishing_pole_equipped)
return;
int weapon_type = get_unicorn_melee_weapon_type();
if (weapon_type == -1) return;
if (weapon_type == -1)
return;
int attack_cooldown = 1000;
if (weapon_type == ADVENTURE_WEAPON_SPEAR) attack_cooldown = 800;
if (weapon_type == ADVENTURE_WEAPON_AXE) attack_cooldown = 1600;
if (weapon_type == ADVENTURE_WEAPON_SPEAR)
attack_cooldown = 800;
if (weapon_type == ADVENTURE_WEAPON_AXE)
attack_cooldown = 1600;
if (ctrl_down && arena_attack_timer.elapsed > attack_cooldown) {
arena_attack_timer.restart();
@@ -380,8 +391,10 @@ void handle_player_actions() {
}
int get_unicorn_melee_weapon_type() {
if (spear_equipped) return ADVENTURE_WEAPON_SPEAR;
if (axe_equipped) return ADVENTURE_WEAPON_AXE;
if (spear_equipped)
return ADVENTURE_WEAPON_SPEAR;
if (axe_equipped)
return ADVENTURE_WEAPON_AXE;
return -1;
}
@@ -438,7 +451,8 @@ int find_unicorn_ranged_target(int player_x, int direction, int range) {
for (int dist = 1; dist <= range; dist++) {
int check_x = player_x + (dist * direction);
if (check_x < 0 || check_x >= UNICORN_ARENA_SIZE) break;
if (check_x < 0 || check_x >= UNICORN_ARENA_SIZE)
break;
if (bridge_supports_health[0] > 0 && check_x == BRIDGE_START) {
return check_x;
@@ -454,7 +468,8 @@ int find_unicorn_ranged_target(int player_x, int direction, int range) {
int unicorn_ranged_attack(int player_x, int direction, int range, int weapon_type, int damage) {
int target_x = find_unicorn_ranged_target(player_x, direction, range);
if (target_x == -1) return -1;
if (target_x == -1)
return -1;
if (target_x == unicorn.x) {
apply_unicorn_damage(damage);
@@ -482,7 +497,8 @@ int unicorn_ranged_attack(int player_x, int direction, int range, int weapon_typ
}
void mark_unicorn_defeated(bool by_fall) {
if (unicorn_defeated) return;
if (unicorn_defeated)
return;
unicorn_defeated = true;
unicorn_defeated_by_fall = by_fall;
if (by_fall) {
@@ -491,8 +507,10 @@ void mark_unicorn_defeated(bool by_fall) {
}
void apply_unicorn_damage(int damage) {
if (damage <= 0) return;
if (unicorn.health <= 0) return;
if (damage <= 0)
return;
if (unicorn.health <= 0)
return;
unicorn.health -= damage;
if (unicorn.health <= 0) {
@@ -501,12 +519,15 @@ void apply_unicorn_damage(int damage) {
}
}
bool pet_find_unicorn_target(int originPos, int referencePos, int &out targetPos, string &out targetLabel, int &out targetKind) {
bool pet_find_unicorn_target(int originPos, int referencePos, int& out targetPos, string& out targetLabel,
int& out targetKind) {
targetPos = -1;
targetLabel = "";
targetKind = -1;
if (unicorn.health <= 0) return false;
if (abs(unicorn.x - originPos) > PET_RANGE) return false;
if (unicorn.health <= 0)
return false;
if (abs(unicorn.x - originPos) > PET_RANGE)
return false;
targetPos = unicorn.x;
targetLabel = "unicorn";
targetKind = 0;
@@ -514,7 +535,8 @@ bool pet_find_unicorn_target(int originPos, int referencePos, int &out targetPos
}
bool pet_damage_unicorn_target(int targetKind, int targetPos, int damage) {
if (targetKind != 0) return false;
if (targetKind != 0)
return false;
apply_unicorn_damage(damage);
return true;
}
@@ -548,7 +570,7 @@ void check_bridge_collapse() {
void update_unicorn() {
if (unicorn.move_timer.elapsed >= unicorn.speed) {
unicorn.move_timer.restart();
// Move
if (unicorn.facing == 1) {
unicorn.x++;
@@ -563,14 +585,14 @@ void update_unicorn() {
unicorn.x = 0;
}
}
// Bridge Logic
if (unicorn.x >= BRIDGE_START && unicorn.x <= BRIDGE_END && !bridge_collapsed) {
unicorn.on_bridge = true;
} else {
unicorn.on_bridge = false;
}
// Collision with Player
if (unicorn.x == player_arena_x && player_arena_y == 0) {
player_health -= 10;
@@ -588,7 +610,8 @@ void update_unicorn_audio() {
}
// Check if we need to switch sounds (different file or no active sound)
bool need_new_sound = (unicorn.sound_handle == -1 || !p.sound_is_active(unicorn.sound_handle) || current_unicorn_sound != sound_file);
bool need_new_sound =
(unicorn.sound_handle == -1 || !p.sound_is_active(unicorn.sound_handle) || current_unicorn_sound != sound_file);
if (need_new_sound) {
// Stop old sound if playing
@@ -596,7 +619,8 @@ void update_unicorn_audio() {
p.destroy_sound(unicorn.sound_handle);
}
// Start new positioned sound using shared helper
unicorn.sound_handle = play_1d_with_volume_step(sound_file, player_arena_x, unicorn.x, true, UNICORN_SOUND_VOLUME_STEP);
unicorn.sound_handle =
play_1d_with_volume_step(sound_file, player_arena_x, unicorn.x, true, UNICORN_SOUND_VOLUME_STEP);
current_unicorn_sound = sound_file;
} else {
// Update position of existing sound
@@ -630,10 +654,13 @@ void play_unicorn_death_sequence() {
// Pitch ranges from 100 (start) to 50 (end) like normal falling
float height_remaining = float(total_fall - feet_fallen);
float pitch_percent = 50.0 + (50.0 * (height_remaining / float(total_fall)));
if (pitch_percent < 50.0) pitch_percent = 50.0;
if (pitch_percent > 100.0) pitch_percent = 100.0;
if (pitch_percent < 50.0)
pitch_percent = 50.0;
if (pitch_percent > 100.0)
pitch_percent = 100.0;
fall_handle = p.play_extended_1d("sounds/actions/falling.ogg", player_arena_x, unicorn.x, 0, 0, true, 0, 0.0, 0.0, pitch_percent);
fall_handle = p.play_extended_1d("sounds/actions/falling.ogg", player_arena_x, unicorn.x, 0, 0, true, 0,
0.0, 0.0, pitch_percent);
if (fall_handle != -1) {
p.update_sound_positioning_values(fall_handle, -1.0, UNICORN_SOUND_VOLUME_STEP, true);
}
@@ -645,7 +672,8 @@ void play_unicorn_death_sequence() {
if (fall_handle != -1) {
p.destroy_sound(fall_handle);
}
play_1d_with_volume_step("sounds/bosses/unicorn/unicorn_falls.ogg", player_arena_x, unicorn.x, false, UNICORN_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/bosses/unicorn/unicorn_falls.ogg", player_arena_x, unicorn.x, false,
UNICORN_SOUND_VOLUME_STEP);
wait(1500); // Let the impact sound play before cleanup
}
+54 -48
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);
}
@@ -160,7 +162,7 @@ void hit_tree_with_spear(int target_x) {
void update_sling_charge() {
int elapsed = sling_charge_timer.elapsed;
int cycle_time = 1500; // 1.5 seconds
int cycle_time = 1500; // 1.5 seconds
int stage_duration = 500; // 0.5 seconds per stage
// Loop the charge cycle
@@ -184,13 +186,17 @@ void update_sling_charge() {
int get_bow_draw_damage(int elapsed_ms) {
int clamped = elapsed_ms;
if (clamped < 0) clamped = 0;
if (clamped > BOW_DRAW_TIME_MS) clamped = BOW_DRAW_TIME_MS;
if (clamped < 0)
clamped = 0;
if (clamped > BOW_DRAW_TIME_MS)
clamped = BOW_DRAW_TIME_MS;
float ratio = float(clamped) / float(BOW_DRAW_TIME_MS);
int damage = int(ratio * BOW_DAMAGE_MAX);
if (damage < BOW_DAMAGE_MIN) damage = BOW_DAMAGE_MIN;
if (damage > BOW_DAMAGE_MAX) damage = BOW_DAMAGE_MAX;
if (damage < BOW_DAMAGE_MIN)
damage = BOW_DAMAGE_MIN;
if (damage > BOW_DAMAGE_MAX)
damage = BOW_DAMAGE_MAX;
return damage;
}
@@ -213,24 +219,23 @@ void start_bow_shot_audio(int start_x, int end_x, int hit_x, int hit_type, int d
bow_shot_duration_ms = duration_ms;
bow_shot_drop_pending = false;
bow_shot_drop_pos = -1;
if (bow_shot_duration_ms < 1) bow_shot_duration_ms = 1;
if (bow_shot_duration_ms < 1)
bow_shot_duration_ms = 1;
bow_shot_sound_handle = play_1d_with_volume_step(
"sounds/weapons/arrow_flies.ogg",
x,
bow_shot_start_x,
false,
PLAYER_WEAPON_SOUND_VOLUME_STEP
);
bow_shot_sound_handle = play_1d_with_volume_step("sounds/weapons/arrow_flies.ogg", x, bow_shot_start_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
}
void update_bow_shot() {
if (!bow_shot_active) return;
if (bow_shot_duration_ms < 1) bow_shot_duration_ms = 1;
if (!bow_shot_active)
return;
if (bow_shot_duration_ms < 1)
bow_shot_duration_ms = 1;
int elapsed = bow_shot_timer.elapsed;
float progress = float(elapsed) / float(bow_shot_duration_ms);
if (progress > 1.0f) progress = 1.0f;
if (progress > 1.0f)
progress = 1.0f;
int travel = int(float(bow_shot_end_x - bow_shot_start_x) * progress);
int current_pos = bow_shot_start_x + travel;
@@ -245,13 +250,7 @@ void update_bow_shot() {
int drop_pos = bow_shot_drop_pos;
stop_bow_shot_audio();
if (hit_x >= 0) {
play_1d_with_volume_step(
"sounds/weapons/arrow_hit.ogg",
x,
hit_x,
false,
PLAYER_WEAPON_SOUND_VOLUME_STEP
);
play_1d_with_volume_step("sounds/weapons/arrow_hit.ogg", x, hit_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
if (hit_type == BOW_HIT_BANDIT) {
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", x, hit_x, BANDIT_SOUND_VOLUME_STEP);
} else if (hit_type == BOW_HIT_BOAR) {
@@ -283,14 +282,16 @@ void release_bow_attack(int player_x) {
bool hit_bandit = false;
bool hit_flying_creature = false;
bool hit_boar = false;
int target_x = find_ranged_enemy(player_x, BOW_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
int target_x =
find_ranged_enemy(player_x, BOW_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
bool hit_tree = false;
if (target_x == -1) {
for (int dist = 1; dist <= BOW_RANGE; dist++) {
int check_x = player_x + (dist * search_direction);
if (check_x < 0 || check_x >= MAP_SIZE) break;
Tree@ tree = get_tree_at(check_x);
if (check_x < 0 || check_x >= MAP_SIZE)
break;
Tree @tree = get_tree_at(check_x);
if (tree != null && !tree.is_chopped) {
target_x = check_x;
hit_tree = true;
@@ -318,16 +319,16 @@ void release_bow_attack(int player_x) {
hit_type = BOW_HIT_NONE;
}
int end_x = (target_x != -1)
? target_x
: (player_x + (search_direction * (BOW_RANGE + BOW_MISS_EXTRA_TILES)));
int end_x = (target_x != -1) ? target_x : (player_x + (search_direction * (BOW_RANGE + BOW_MISS_EXTRA_TILES)));
int duration_ms = ARROW_FLIES_DURATION_MS;
if (target_x != -1) {
int distance = abs(target_x - player_x);
if (distance < 1) distance = 1;
if (distance < 1)
distance = 1;
duration_ms = int(float(ARROW_FLIES_DURATION_MS) * (float(distance) / float(BOW_RANGE)));
if (duration_ms < 1) duration_ms = 1;
if (duration_ms < 1)
duration_ms = 1;
}
int hit_x = (target_x != -1) ? target_x : -1;
@@ -349,7 +350,6 @@ void release_sling_attack(int player_x) {
// Only hit if released during in-range window (stage 1)
if (stage != 1) {
speak_with_history("Stone missed.", true);
return;
}
@@ -359,17 +359,20 @@ void release_sling_attack(int player_x) {
bool hit_bandit = false;
bool hit_flying_creature = false;
bool hit_boar = false;
target_x = find_ranged_enemy(player_x, SLING_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
target_x =
find_ranged_enemy(player_x, SLING_RANGE, search_direction, true, hit_bandit, hit_boar, hit_flying_creature);
// If no enemy found, check for trees (but don't damage them)
if (target_x == -1) {
for (int dist = 1; dist <= SLING_RANGE; dist++) {
int check_x = player_x + (dist * search_direction);
if (check_x < 0 || check_x >= MAP_SIZE) break;
Tree@ tree = get_tree_at(check_x);
if (check_x < 0 || check_x >= MAP_SIZE)
break;
Tree @tree = get_tree_at(check_x);
if (tree != null && !tree.is_chopped) {
// Stone hits tree but doesn't damage it
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, check_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, check_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
return;
}
}
@@ -377,7 +380,6 @@ void release_sling_attack(int player_x) {
// No target found
if (target_x == -1) {
speak_with_history("Stone missed.", true);
return;
}
@@ -387,19 +389,23 @@ void release_sling_attack(int player_x) {
// Damage the correct enemy type
if (hit_bandit) {
damage_bandit_at(target_x, damage);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", player_x, target_x, BANDIT_SOUND_VOLUME_STEP);
} else if (hit_boar) {
damage_boar_at(target_x, damage);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", player_x, target_x, BOAR_SOUND_VOLUME_STEP);
} else if (hit_flying_creature) {
damage_flying_creature_at(target_x, damage);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
// Falling sound handled by damage_flying_creature_at
} else {
damage_zombie_at(target_x, damage);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false, PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_1d_with_volume_step("sounds/weapons/sling_hit.ogg", player_x, target_x, false,
PLAYER_WEAPON_SOUND_VOLUME_STEP);
play_creature_hit_sound("sounds/enemies/zombie_hit.ogg", player_x, target_x, ZOMBIE_SOUND_VOLUME_STEP);
}
}
+39 -38
View File
@@ -1,14 +1,14 @@
// Map configuration
int MAP_SIZE = 35;
const int BASE_END = 4; // 0-4
const int GRASS_END = 19; // 5-19
const int BASE_END = 4; // 0-4
const int GRASS_END = 19; // 5-19
const int GRAVEL_START = 20; // 20-34
const int GRAVEL_END = 34; // 20-34
const int GRAVEL_END = 34; // 20-34
// Expansion configuration
const int EXPANSION_SIZE = 30;
const int EXPANSION_CHANCE = 30; // 30% chance per hour before noon
int expanded_area_start = -1; // -1 means not expanded yet
int expanded_area_start = -1; // -1 means not expanded yet
int expanded_area_end = -1;
// Movement configuration
@@ -193,28 +193,28 @@ const float MASTER_VOLUME_MAX_DB = 0.0;
const float MASTER_VOLUME_MIN_DB = -60.0;
const float MASTER_VOLUME_STEP_DB = 3.0;
const int SNARE_SOUND_RANGE = 2;
const float SNARE_SOUND_VOLUME_STEP = 4.0; // More audible for locating snares
const float SNARE_SOUND_PAN_STEP = 4.0; // Stronger pan for direction
const float SNARE_SOUND_VOLUME_STEP = 4.0; // More audible for locating snares
const float SNARE_SOUND_PAN_STEP = 4.0; // Stronger pan for direction
const int SNARE_COLLECT_RANGE = 1;
const int FIRE_SOUND_RANGE = 3;
const float FIRE_SOUND_VOLUME_STEP = 5.0; // 15 dB over 3 tiles (FIRE_SOUND_RANGE)
const float FIRE_SOUND_VOLUME_STEP = 5.0; // 15 dB over 3 tiles (FIRE_SOUND_RANGE)
const int FIREPIT_SOUND_RANGE = 5;
const float FIREPIT_SOUND_VOLUME_STEP = 6.0; // 30 dB over 5 tiles
const float FIREPIT_SOUND_VOLUME_STEP = 6.0; // 30 dB over 5 tiles
const int STREAM_SOUND_RANGE = 7;
const float STREAM_SOUND_VOLUME_STEP = 4.3; // 30 dB over 7 tiles
const float STREAM_SOUND_VOLUME_STEP = 4.3; // 30 dB over 7 tiles
const float TREE_SOUND_VOLUME_STEP = 4.0; // Similar to snares for good audibility
const float TREE_SOUND_VOLUME_STEP = 4.0; // Similar to snares for good audibility
const int TREE_SOUND_RANGE = 4;
const int TREE_MIN_DISTANCE = 10;
const int TREE_MAX_PER_AREA = 2;
const int TREE_AVOID_STEEP_CLIMB_RANGE = 3;
const float RESIDENT_DEFENSE_VOLUME_STEP = 3.0; // Default volume for resident counter-attacks
const float RESIDENT_DEFENSE_VOLUME_STEP = 3.0; // Default volume for resident counter-attacks
const float PLAYER_WEAPON_SOUND_VOLUME_STEP = 3.0;
const int FLYING_CREATURE_FADE_OUT_DURATION = 1500; // ms
const int FLYING_CREATURE_FADE_OUT_DURATION = 1500; // ms
const float FLYING_CREATURE_FADE_OUT_MIN_VOLUME = -40.0; // dB
// Mountain configuration
@@ -225,7 +225,7 @@ const int MOUNTAIN_STEEP_THRESHOLD = 7;
const int MOUNTAIN_MAX_SLOPE = 20;
const int ROPE_CLIMB_SPEED = 1000;
const int MOUNTAIN_STREAM_SOUND_RANGE = 7;
const float MOUNTAIN_STREAM_VOLUME_STEP = 4.3; // 30 dB over 7 tiles
const float MOUNTAIN_STREAM_VOLUME_STEP = 4.3; // 30 dB over 7 tiles
const int QUEST_MAX_ACTIVE = 4;
const int QUEST_CHANCE_PER_FAVOR = 10;
const int QUEST_MIN_CHANCE = 5;
@@ -235,20 +235,20 @@ const int QUEST_LOG_SCORE = 10;
const int QUEST_SKIN_SCORE = 14;
// Resident settings
const int MAX_RESIDENTS = 4; // Max residents per base (+ player = 5 total)
const int MAX_RESIDENTS = 4; // Max residents per base (+ player = 5 total)
const int RESIDENT_WEAPON_BREAK_CHANCE = 10;
const int RESIDENT_SPEAR_DAMAGE = 2;
const int RESIDENT_SLING_DAMAGE_MIN = 3;
const int RESIDENT_SLING_DAMAGE_MAX = 5;
const int RESIDENT_BOW_DAMAGE_MIN = 4;
const int RESIDENT_BOW_DAMAGE_MAX = 6;
const int RESIDENT_COMBAT_BASE_COOLDOWN = 3200; // Base attack delay (2x player axe)
const int RESIDENT_COMBAT_TARGET_COOLDOWN = 1600; // At max horses, about player axe speed
const int RESIDENT_SNARE_ESCAPE_CHANCE = 5; // 5% chance game escapes when resident retrieves
const int RESIDENT_SNARE_CHECK_CHANCE = 15; // 15% chance per hour to check snares
const int RESIDENT_FISHING_CHANCE = 6; // 6% chance per resident per hour to catch a fish
const int RESIDENT_SMOKE_FISH_CHANCE = 10; // 10% chance per hour to smoke a stored fish
const int RESIDENT_TOOL_BREAK_CHANCE = 2; // 2% chance tools break during resident use (fishing poles, knives, baskets)
const int RESIDENT_COMBAT_BASE_COOLDOWN = 3200; // Base attack delay (2x player axe)
const int RESIDENT_COMBAT_TARGET_COOLDOWN = 1600; // At max horses, about player axe speed
const int RESIDENT_SNARE_ESCAPE_CHANCE = 5; // 5% chance game escapes when resident retrieves
const int RESIDENT_SNARE_CHECK_CHANCE = 15; // 15% chance per hour to check snares
const int RESIDENT_FISHING_CHANCE = 6; // 6% chance per resident per hour to catch a fish
const int RESIDENT_SMOKE_FISH_CHANCE = 10; // 10% chance per hour to smoke a stored fish
const int RESIDENT_TOOL_BREAK_CHANCE = 2; // 2% chance tools break during resident use (fishing poles, knives, baskets)
const int RESIDENT_CLOTHING_REPAIR_COST = 5;
const float PLAYER_ITEM_BREAK_CHANCE_MIN = 1.0;
const float PLAYER_ITEM_BREAK_CHANCE_MAX = 100.0;
@@ -266,8 +266,8 @@ const int PET_LOYALTY_MAX = 10;
const int PET_ATTACK_COOLDOWN = 1600; // Same as axe
const int PET_RETRIEVE_COOLDOWN = 1000;
const int PET_RANDOM_FIND_CHANCE = 20; // Percent per hour when loyalty is high
const int PET_ADVENTURE_CHANCE = 5; // Percent chance after adventure victory
const int PET_TREE_HAWK_CHANCE = 10; // Percent chance after reaching top of a tree
const int PET_ADVENTURE_CHANCE = 5; // Percent chance after adventure victory
const int PET_TREE_HAWK_CHANCE = 10; // Percent chance after reaching top of a tree
const int PET_LOYALTY_BONUS_THRESHOLD = 5;
const int PET_TRAVEL_MIN_MS = 100;
const int PET_RANGE = BOW_RANGE + 2;
@@ -277,18 +277,19 @@ const int PET_KNOCKOUT_COOLDOWN_HOURS = 4;
const float PET_CHARGE_SPEED_MULTIPLIER = 1.5;
const int PET_FOLLOW_COMFORT_DISTANCE = 2;
const int PET_FOLLOW_MAX_DISTANCE = 5;
const int PET_LEAVE_DESPAWN_DISTANCE = 20;
// Goose settings
const int GOOSE_HEALTH = 1;
const int GOOSE_MOVE_INTERVAL_MIN = 800; // Faster movement
const int GOOSE_MOVE_INTERVAL_MIN = 800; // Faster movement
const int GOOSE_MOVE_INTERVAL_MAX = 2000;
const int GOOSE_FLYING_HEIGHT_MIN = 10;
const int GOOSE_FLYING_HEIGHT_MAX = 30;
const float GOOSE_SOUND_VOLUME_STEP = 3.0;
const int GOOSE_FLIGHT_SOUND_DELAY_MIN = 2000; // Honk more often
const int GOOSE_FLIGHT_SOUND_DELAY_MAX = 5000;
const int GOOSE_FALL_SPEED = 100; // ms per foot
const int GOOSE_FLY_AWAY_CHANCE = 0; // Chance out of 1000 per tick to fly away
const int GOOSE_FALL_SPEED = 100; // ms per foot
const int GOOSE_FLY_AWAY_CHANCE = 0; // Chance out of 1000 per tick to fly away
const int GOOSE_MAX_DIST_FROM_WATER = 4; // How far they can wander from water
const int GOOSE_MAX_COUNT = 3;
const int GOOSE_HOURLY_SPAWN_CHANCE = 40; // Percent chance per hour to spawn a goose
@@ -303,28 +304,28 @@ const int TURKEY_FLYING_HEIGHT_MAX = 30;
const float TURKEY_SOUND_VOLUME_STEP = 3.0;
const int TURKEY_FLIGHT_SOUND_DELAY_MIN = 2000;
const int TURKEY_FLIGHT_SOUND_DELAY_MAX = 5000;
const int TURKEY_FALL_SPEED = 100; // ms per foot
const int TURKEY_FLY_AWAY_CHANCE = 0; // Chance out of 1000 per tick to fly away
const int TURKEY_FALL_SPEED = 100; // ms per foot
const int TURKEY_FLY_AWAY_CHANCE = 0; // Chance out of 1000 per tick to fly away
const int TURKEY_MAX_DIST_FROM_FOREST = 0; // How far they can wander from forest
const int TURKEY_MAX_COUNT = 3;
const int TURKEY_HOURLY_SPAWN_CHANCE = 40; // Percent chance per hour to spawn a turkey
const int TURKEY_SIGHT_RANGE = 0;
// Weather settings
const int WEATHER_FADE_DURATION = 8000; // 8 seconds for smooth audio transitions
const int WEATHER_FADE_DURATION = 8000; // 8 seconds for smooth audio transitions
const float WEATHER_MIN_VOLUME = -30.0;
const float WEATHER_MAX_VOLUME = 0.0;
const float RAIN_VOLUME_LIGHT = -18.0;
const float RAIN_VOLUME_MODERATE = -10.0;
const float RAIN_VOLUME_HEAVY = -3.0;
const int WIND_GUST_MIN_DELAY = 30000; // Min 30 seconds between gusts
const int WIND_GUST_MAX_DELAY = 60000; // Max 60 seconds between gusts
const int THUNDER_MIN_INTERVAL = 8000; // Min 8 seconds between thunder
const int THUNDER_MAX_INTERVAL = 35000; // Max 35 seconds between thunder
const int THUNDER_MOVEMENT_SPEED = 250; // ms per tile movement (faster roll across sky)
const float THUNDER_SOUND_VOLUME_STEP = 0.5; // Gentler volume falloff
const int THUNDER_SPAWN_DISTANCE_MIN = 0; // Min distance from player
const int THUNDER_SPAWN_DISTANCE_MAX = 20; // Max distance from player
const int WIND_GUST_MIN_DELAY = 30000; // Min 30 seconds between gusts
const int WIND_GUST_MAX_DELAY = 60000; // Max 60 seconds between gusts
const int THUNDER_MIN_INTERVAL = 8000; // Min 8 seconds between thunder
const int THUNDER_MAX_INTERVAL = 35000; // Max 35 seconds between thunder
const int THUNDER_MOVEMENT_SPEED = 250; // ms per tile movement (faster roll across sky)
const float THUNDER_SOUND_VOLUME_STEP = 0.5; // Gentler volume falloff
const int THUNDER_SPAWN_DISTANCE_MIN = 0; // Min distance from player
const int THUNDER_SPAWN_DISTANCE_MAX = 20; // Max distance from player
const int CHANCE_CLEAR_TO_WINDY = 15;
const int CHANCE_CLEAR_TO_RAINY = 6;
const int CHANCE_CLEAR_TO_STORMY = 5;
@@ -357,7 +358,7 @@ const int FALL_DAMAGE_MAX = 4;
// Base Automation
const int RESIDENT_COLLECTION_CHANCE = 10; // 10% chance per basket per hour
const int RESIDENT_FORAGING_CHANCE = 50; // 50% chance per resident per attempt (daily)
const int RESIDENT_FORAGING_CHANCE = 50; // 50% chance per resident per attempt (daily)
// Utility functions
int abs(int value) {
+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);
+130 -71
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)",
"Skin Gloves (1 Skin, 1 Vine)",
"Skin Pants (6 Skins, 3 Vines)",
"Skin Tunic (4 Skins, 2 Vines)",
"Moccasins (2 Skins, 1 Vine)",
"Skin Pouch (2 Skins, 1 Vine)",
"Backpack (11 Skins, 5 Vines, 4 Skin Pouches)"
};
string[] options = {"Skin Hat (1 Skin, 1 Vine)",
"Skin Gloves (1 Skin, 1 Vine)",
"Skin Pants (6 Skins, 3 Vines)",
"Skin Tunic (4 Skins, 2 Vines)",
"Moccasins (2 Skins, 1 Vine)",
"Skin Pouch (2 Skins, 1 Vine)",
"Backpack (11 Skins, 5 Vines, 4 Skin Pouches)"};
speak_with_history("Clothing. " + options[selection], true);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -68,38 +66,54 @@ void run_clothing_menu() {
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= options.length()) selection = 0;
if (selection >= options.length())
selection = 0;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = options.length() - 1;
if (selection < 0)
selection = options.length() - 1;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
play_menu_select_sound();
if (selection == 0) craft_skin_hat();
else if (selection == 1) craft_skin_gloves();
else if (selection == 2) craft_skin_pants();
else if (selection == 3) craft_skin_tunic();
else if (selection == 4) craft_moccasins();
else if (selection == 5) craft_skin_pouch();
else if (selection == 6) craft_backpack();
if (selection == 0)
craft_skin_hat();
else if (selection == 1)
craft_skin_gloves();
else if (selection == 2)
craft_skin_pants();
else if (selection == 3)
craft_skin_tunic();
else if (selection == 4)
craft_moccasins();
else if (selection == 5)
craft_skin_pouch();
else if (selection == 6)
craft_backpack();
break;
}
if (key_pressed(KEY_TAB)) {
play_menu_select_sound();
if (selection == 0) craft_skin_hat_max();
else if (selection == 1) craft_skin_gloves_max();
else if (selection == 2) craft_skin_pants_max();
else if (selection == 3) craft_skin_tunic_max();
else if (selection == 4) craft_moccasins_max();
else if (selection == 5) craft_skin_pouch_max();
else if (selection == 6) craft_backpack_max();
if (selection == 0)
craft_skin_hat_max();
else if (selection == 1)
craft_skin_gloves_max();
else if (selection == 2)
craft_skin_pants_max();
else if (selection == 3)
craft_skin_tunic_max();
else if (selection == 4)
craft_moccasins_max();
else if (selection == 5)
craft_skin_pouch_max();
else if (selection == 6)
craft_backpack_max();
break;
}
}
@@ -107,8 +121,10 @@ void run_clothing_menu() {
void craft_skin_hat() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 1)
missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
if (missing == "") {
if (get_personal_count(ITEM_SKIN_HATS) >= get_personal_stack_limit()) {
@@ -134,15 +150,19 @@ void craft_skin_hat_max() {
int max_by_skins = get_personal_count(ITEM_SKINS);
int max_by_vines = get_personal_count(ITEM_VINES);
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_HATS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 1)
missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -158,8 +178,10 @@ void craft_skin_hat_max() {
void craft_skin_gloves() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 1)
missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
if (missing == "") {
if (get_personal_count(ITEM_SKIN_GLOVES) >= get_personal_stack_limit()) {
@@ -185,15 +207,19 @@ void craft_skin_gloves_max() {
int max_by_skins = get_personal_count(ITEM_SKINS);
int max_by_vines = get_personal_count(ITEM_VINES);
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_GLOVES);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 1) missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 1)
missing += "1 skin ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -209,8 +235,10 @@ void craft_skin_gloves_max() {
void craft_skin_pants() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
if (get_personal_count(ITEM_VINES) < 3) missing += "3 vines ";
if (get_personal_count(ITEM_SKINS) < 6)
missing += "6 skins ";
if (get_personal_count(ITEM_VINES) < 3)
missing += "3 vines ";
if (missing == "") {
if (get_personal_count(ITEM_SKIN_PANTS) >= get_personal_stack_limit()) {
@@ -236,15 +264,19 @@ void craft_skin_pants_max() {
int max_by_skins = get_personal_count(ITEM_SKINS) / 6;
int max_by_vines = get_personal_count(ITEM_VINES) / 3;
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_PANTS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
if (get_personal_count(ITEM_VINES) < 3) missing += "3 vines ";
if (get_personal_count(ITEM_SKINS) < 6)
missing += "6 skins ";
if (get_personal_count(ITEM_VINES) < 3)
missing += "3 vines ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -259,8 +291,10 @@ void craft_skin_pants_max() {
void craft_skin_tunic() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 4) missing += "4 skins ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_SKINS) < 4)
missing += "4 skins ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
if (missing == "") {
if (get_personal_count(ITEM_SKIN_TUNICS) >= get_personal_stack_limit()) {
@@ -286,15 +320,19 @@ void craft_skin_tunic_max() {
int max_by_skins = get_personal_count(ITEM_SKINS) / 4;
int max_by_vines = get_personal_count(ITEM_VINES) / 2;
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_TUNICS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 4) missing += "4 skins ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_SKINS) < 4)
missing += "4 skins ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -309,8 +347,10 @@ void craft_skin_tunic_max() {
void craft_moccasins() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
if (missing == "") {
if (get_personal_count(ITEM_MOCCASINS) >= get_personal_stack_limit()) {
@@ -336,15 +376,19 @@ void craft_moccasins_max() {
int max_by_skins = get_personal_count(ITEM_SKINS) / 2;
int max_by_vines = get_personal_count(ITEM_VINES);
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_MOCCASINS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -360,8 +404,10 @@ void craft_moccasins_max() {
void craft_skin_pouch() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
if (missing == "") {
if (get_personal_count(ITEM_SKIN_POUCHES) >= get_personal_stack_limit()) {
@@ -387,15 +433,19 @@ void craft_skin_pouch_max() {
int max_by_skins = get_personal_count(ITEM_SKINS) / 2;
int max_by_vines = get_personal_count(ITEM_VINES);
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SKIN_POUCHES);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1) missing += "1 vine ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 1)
missing += "1 vine ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -411,9 +461,12 @@ void craft_skin_pouch_max() {
void craft_backpack() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 11) missing += "11 skins ";
if (get_personal_count(ITEM_VINES) < 5) missing += "5 vines ";
if (get_total_pouch_count() < 4) missing += "4 skin pouches ";
if (get_personal_count(ITEM_SKINS) < 11)
missing += "11 skins ";
if (get_personal_count(ITEM_VINES) < 5)
missing += "5 vines ";
if (get_total_pouch_count() < 4)
missing += "4 skin pouches ";
if (missing == "") {
if (get_personal_count(ITEM_BACKPACKS) >= get_personal_stack_limit()) {
@@ -441,17 +494,23 @@ void craft_backpack_max() {
int max_by_vines = get_personal_count(ITEM_VINES) / 5;
int max_by_pouches = get_total_pouch_count() / 4;
int max_craft = max_by_skins;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_pouches < max_craft) max_craft = max_by_pouches;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
if (max_by_pouches < max_craft)
max_craft = max_by_pouches;
int space = get_personal_stack_limit() - get_personal_count(ITEM_BACKPACKS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 11) missing += "11 skins ";
if (get_personal_count(ITEM_VINES) < 5) missing += "5 vines ";
if (get_total_pouch_count() < 4) missing += "4 skin pouches ";
if (get_personal_count(ITEM_SKINS) < 11)
missing += "11 skins ";
if (get_personal_count(ITEM_VINES) < 5)
missing += "5 vines ";
if (get_total_pouch_count() < 4)
missing += "4 skin pouches ";
speak_with_history("Missing: " + missing, true);
return;
}
+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);
}
+140 -78
View File
@@ -1,20 +1,18 @@
// Crafting tools
void run_tools_menu() {
int selection = 0;
string[] options = {
"Stone Knife (2 Stones)",
"Snare (1 Stick, 2 Vines)",
"Stone Axe (1 Stick, 1 Vine, 2 Stones) [Requires Knife]",
"Fishing Pole (1 Stick, 2 Vines)",
"Rope (3 Vines)",
"Quiver (2 Skins, 2 Vines)",
"Canoe (4 Logs, 11 Sticks, 11 Vines, 6 Skins, 2 Rope, 6 Reeds)",
"Reed Basket (3 Reeds)",
"Clay Pot (3 Clay)"
};
string[] options = {"Stone Knife (2 Stones)",
"Snare (1 Stick, 2 Vines)",
"Stone Axe (1 Stick, 1 Vine, 2 Stones) [Requires Knife]",
"Fishing Pole (1 Stick, 2 Vines)",
"Rope (3 Vines)",
"Quiver (2 Skins, 2 Vines)",
"Canoe (4 Logs, 11 Sticks, 11 Vines, 6 Skins, 2 Rope, 6 Reeds)",
"Reed Basket (3 Reeds)",
"Clay Pot (3 Clay)"};
speak_with_history("Tools. " + options[selection], true);
while(true) {
while (true) {
wait(5);
if (menu_background_tick()) {
return;
@@ -27,42 +25,62 @@ void run_tools_menu() {
if (key_pressed(KEY_DOWN)) {
play_menu_move_sound();
selection++;
if (selection >= options.length()) selection = 0;
if (selection >= options.length())
selection = 0;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
play_menu_move_sound();
selection--;
if (selection < 0) selection = options.length() - 1;
if (selection < 0)
selection = options.length() - 1;
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
play_menu_select_sound();
if (selection == 0) craft_knife();
else if (selection == 1) craft_snare();
else if (selection == 2) craft_axe();
else if (selection == 3) craft_fishing_pole();
else if (selection == 4) craft_rope();
else if (selection == 5) craft_quiver();
else if (selection == 6) craft_canoe();
else if (selection == 7) craft_reed_basket();
else if (selection == 8) craft_clay_pot();
if (selection == 0)
craft_knife();
else if (selection == 1)
craft_snare();
else if (selection == 2)
craft_axe();
else if (selection == 3)
craft_fishing_pole();
else if (selection == 4)
craft_rope();
else if (selection == 5)
craft_quiver();
else if (selection == 6)
craft_canoe();
else if (selection == 7)
craft_reed_basket();
else if (selection == 8)
craft_clay_pot();
break;
}
if (key_pressed(KEY_TAB)) {
play_menu_select_sound();
if (selection == 0) craft_knife_max();
else if (selection == 1) craft_snare_max();
else if (selection == 2) craft_axe_max();
else if (selection == 3) craft_fishing_pole_max();
else if (selection == 4) craft_rope_max();
else if (selection == 5) craft_quiver_max();
else if (selection == 6) craft_canoe_max();
else if (selection == 7) craft_reed_basket_max();
else if (selection == 8) craft_clay_pot_max();
if (selection == 0)
craft_knife_max();
else if (selection == 1)
craft_snare_max();
else if (selection == 2)
craft_axe_max();
else if (selection == 3)
craft_fishing_pole_max();
else if (selection == 4)
craft_rope_max();
else if (selection == 5)
craft_quiver_max();
else if (selection == 6)
craft_canoe_max();
else if (selection == 7)
craft_reed_basket_max();
else if (selection == 8)
craft_clay_pot_max();
break;
}
}
@@ -70,7 +88,8 @@ void run_tools_menu() {
void craft_knife() {
string missing = "";
if (get_personal_count(ITEM_STONES) < 2) missing += "2 stones ";
if (get_personal_count(ITEM_STONES) < 2)
missing += "2 stones ";
if (missing == "") {
if (get_personal_count(ITEM_KNIVES) >= get_personal_stack_limit()) {
@@ -94,7 +113,8 @@ void craft_knife_max() {
int max_possible = get_personal_count(ITEM_STONES) / 2;
int space = get_personal_stack_limit() - get_personal_count(ITEM_KNIVES);
if (max_possible > space) max_possible = space;
if (max_possible > space)
max_possible = space;
if (max_possible <= 0) {
speak_with_history("Missing: 2 stones", true);
@@ -111,8 +131,10 @@ void craft_knife_max() {
void craft_snare() {
string missing = "";
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_STICKS) < 1)
missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
if (missing == "") {
if (get_personal_count(ITEM_SNARES) >= get_personal_stack_limit()) {
@@ -138,15 +160,19 @@ void craft_snare_max() {
int max_by_sticks = get_personal_count(ITEM_STICKS);
int max_by_vines = get_personal_count(ITEM_VINES) / 2;
int max_craft = max_by_sticks;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_SNARES);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_STICKS) < 1)
missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -162,8 +188,10 @@ void craft_snare_max() {
void craft_fishing_pole() {
string missing = "";
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_STICKS) < 1)
missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
if (missing == "") {
if (get_personal_count(ITEM_FISHING_POLES) >= get_personal_stack_limit()) {
@@ -189,15 +217,19 @@ void craft_fishing_pole_max() {
int max_by_sticks = get_personal_count(ITEM_STICKS);
int max_by_vines = get_personal_count(ITEM_VINES) / 2;
int max_craft = max_by_sticks;
if (max_by_vines < max_craft) max_craft = max_by_vines;
if (max_by_vines < max_craft)
max_craft = max_by_vines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_FISHING_POLES);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
string missing = "";
if (get_personal_count(ITEM_STICKS) < 1) missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_STICKS) < 1)
missing += "1 stick ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -213,7 +245,8 @@ void craft_fishing_pole_max() {
void craft_rope() {
string missing = "";
if (get_personal_count(ITEM_VINES) < 3) missing += "3 vines ";
if (get_personal_count(ITEM_VINES) < 3)
missing += "3 vines ";
if (missing == "") {
if (get_personal_count(ITEM_ROPES) >= get_personal_stack_limit()) {
@@ -238,7 +271,8 @@ void craft_rope_max() {
int max_craft = get_personal_count(ITEM_VINES) / 3;
int space = get_personal_stack_limit() - get_personal_count(ITEM_ROPES);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
speak_with_history("Missing: 3 vines", true);
@@ -255,8 +289,10 @@ void craft_rope_max() {
void craft_quiver() {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
if (missing == "") {
if (get_personal_count(ITEM_QUIVERS) >= get_personal_stack_limit()) {
@@ -282,15 +318,19 @@ void craft_quiver_max() {
int maxBySkins = get_personal_count(ITEM_SKINS) / 2;
int maxByVines = get_personal_count(ITEM_VINES) / 2;
int maxCraft = maxBySkins;
if (maxByVines < maxCraft) maxCraft = maxByVines;
if (maxByVines < maxCraft)
maxCraft = maxByVines;
int space = get_personal_stack_limit() - get_personal_count(ITEM_QUIVERS);
if (maxCraft > space) maxCraft = space;
if (maxCraft > space)
maxCraft = space;
if (maxCraft <= 0) {
string missing = "";
if (get_personal_count(ITEM_SKINS) < 2) missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 2) missing += "2 vines ";
if (get_personal_count(ITEM_SKINS) < 2)
missing += "2 skins ";
if (get_personal_count(ITEM_VINES) < 2)
missing += "2 vines ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -306,12 +346,18 @@ void craft_quiver_max() {
void craft_canoe() {
string missing = "";
if (get_personal_count(ITEM_LOGS) < 4) missing += "4 logs ";
if (get_personal_count(ITEM_STICKS) < 11) missing += "11 sticks ";
if (get_personal_count(ITEM_VINES) < 11) missing += "11 vines ";
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
if (get_personal_count(ITEM_ROPES) < 2) missing += "2 rope ";
if (get_personal_count(ITEM_REEDS) < 6) missing += "6 reeds ";
if (get_personal_count(ITEM_LOGS) < 4)
missing += "4 logs ";
if (get_personal_count(ITEM_STICKS) < 11)
missing += "11 sticks ";
if (get_personal_count(ITEM_VINES) < 11)
missing += "11 vines ";
if (get_personal_count(ITEM_SKINS) < 6)
missing += "6 skins ";
if (get_personal_count(ITEM_ROPES) < 2)
missing += "2 rope ";
if (get_personal_count(ITEM_REEDS) < 6)
missing += "6 reeds ";
if (missing == "") {
if (get_personal_count(ITEM_CANOES) >= get_personal_stack_limit()) {
@@ -345,23 +391,35 @@ void craft_canoe_max() {
int maxByRopes = get_personal_count(ITEM_ROPES) / 2;
int maxByReeds = get_personal_count(ITEM_REEDS) / 6;
int maxCraft = maxByLogs;
if (maxBySticks < maxCraft) maxCraft = maxBySticks;
if (maxByVines < maxCraft) maxCraft = maxByVines;
if (maxBySkins < maxCraft) maxCraft = maxBySkins;
if (maxByRopes < maxCraft) maxCraft = maxByRopes;
if (maxByReeds < maxCraft) maxCraft = maxByReeds;
if (maxBySticks < maxCraft)
maxCraft = maxBySticks;
if (maxByVines < maxCraft)
maxCraft = maxByVines;
if (maxBySkins < maxCraft)
maxCraft = maxBySkins;
if (maxByRopes < maxCraft)
maxCraft = maxByRopes;
if (maxByReeds < maxCraft)
maxCraft = maxByReeds;
int space = get_personal_stack_limit() - get_personal_count(ITEM_CANOES);
if (maxCraft > space) maxCraft = space;
if (maxCraft > space)
maxCraft = space;
if (maxCraft <= 0) {
string missing = "";
if (get_personal_count(ITEM_LOGS) < 4) missing += "4 logs ";
if (get_personal_count(ITEM_STICKS) < 11) missing += "11 sticks ";
if (get_personal_count(ITEM_VINES) < 11) missing += "11 vines ";
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
if (get_personal_count(ITEM_ROPES) < 2) missing += "2 rope ";
if (get_personal_count(ITEM_REEDS) < 6) missing += "6 reeds ";
if (get_personal_count(ITEM_LOGS) < 4)
missing += "4 logs ";
if (get_personal_count(ITEM_STICKS) < 11)
missing += "11 sticks ";
if (get_personal_count(ITEM_VINES) < 11)
missing += "11 vines ";
if (get_personal_count(ITEM_SKINS) < 6)
missing += "6 skins ";
if (get_personal_count(ITEM_ROPES) < 2)
missing += "2 rope ";
if (get_personal_count(ITEM_REEDS) < 6)
missing += "6 reeds ";
speak_with_history("Missing: " + missing, true);
return;
}
@@ -381,7 +439,8 @@ void craft_canoe_max() {
void craft_reed_basket() {
string missing = "";
if (get_personal_count(ITEM_REEDS) < 3) missing += "3 reeds ";
if (get_personal_count(ITEM_REEDS) < 3)
missing += "3 reeds ";
if (missing == "") {
if (get_personal_count(ITEM_REED_BASKETS) >= get_personal_stack_limit()) {
@@ -406,7 +465,8 @@ void craft_reed_basket_max() {
int max_craft = get_personal_count(ITEM_REEDS) / 3;
int space = get_personal_stack_limit() - get_personal_count(ITEM_REED_BASKETS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
speak_with_history("Missing: 3 reeds", true);
@@ -423,10 +483,11 @@ void craft_reed_basket_max() {
void craft_clay_pot() {
string missing = "";
if (get_personal_count(ITEM_CLAY) < 3) missing += "3 clay ";
if (get_personal_count(ITEM_CLAY) < 3)
missing += "3 clay ";
// Check for fire within 3 tiles (can hear it)
WorldFire@ fire = get_fire_within_range(x, 3);
WorldFire @fire = get_fire_within_range(x, 3);
if (fire == null) {
speak_with_history("You need a fire within 3 tiles to craft a clay pot.", true);
return;
@@ -448,7 +509,7 @@ void craft_clay_pot() {
void craft_clay_pot_max() {
// Check for fire within 3 tiles (can hear it)
WorldFire@ fire = get_fire_within_range(x, 3);
WorldFire @fire = get_fire_within_range(x, 3);
if (fire == null) {
speak_with_history("You need a fire within 3 tiles to craft clay pots.", true);
return;
@@ -462,7 +523,8 @@ void craft_clay_pot_max() {
int max_craft = get_personal_count(ITEM_CLAY) / 3;
int space = get_personal_stack_limit() - get_personal_count(ITEM_CLAY_POTS);
if (max_craft > space) max_craft = space;
if (max_craft > space)
max_craft = space;
if (max_craft <= 0) {
speak_with_history("Missing: 3 clay", true);
+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);
}
+78 -46
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;
@@ -49,7 +49,7 @@ class Bandit {
// Wandering behavior properties
string behavior_state; // "aggressive" or "wandering"
int wander_direction; // -1, 0, or 1
int wander_direction; // -1, 0, or 1
timer wander_direction_timer;
int wander_direction_change_interval;
@@ -89,12 +89,12 @@ class Bandit {
// Initialize wandering behavior (start aggressive during invasion)
behavior_state = "aggressive";
wander_direction = 0;
wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
wander_direction_change_interval =
random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
wander_direction_timer.restart();
in_weapon_range = false;
}
}
Bandit@[] bandits;
} Bandit @[] bandits;
void update_bandit_weapon_range_audio() {
for (uint i = 0; i < bandits.length(); i++) {
@@ -104,12 +104,14 @@ void update_bandit_weapon_range_audio() {
bool bandit_range_audio_registered = false;
void ensure_bandit_range_audio_registration() {
if (bandit_range_audio_registered) return;
if (bandit_range_audio_registered)
return;
bandit_range_audio_registered = register_weapon_range_audio_callback(@update_bandit_weapon_range_audio);
}
void clear_bandits() {
if (bandits.length() == 0) return;
if (bandits.length() == 0)
return;
for (uint i = 0; i < bandits.length(); i++) {
force_weapon_range_exit(bandits[i].position, bandits[i].in_weapon_range);
@@ -121,7 +123,7 @@ void clear_bandits() {
bandits.resize(0);
}
Bandit@ get_bandit_at(int pos) {
Bandit @get_bandit_at(int pos) {
for (uint i = 0; i < bandits.length(); i++) {
if (bandits[i].position == pos) {
return @bandits[i];
@@ -141,14 +143,18 @@ int pick_bandit_spawn_position(int range_start, int range_end) {
for (int attempts = 0; attempts < 20; attempts++) {
int candidate = random(start, end);
if (candidate == x) continue;
if (get_bandit_at(candidate) != null) continue;
if (candidate == x)
continue;
if (get_bandit_at(candidate) != null)
continue;
return candidate;
}
for (int candidate = start; candidate <= end; candidate++) {
if (candidate == x) continue;
if (get_bandit_at(candidate) != null) continue;
if (candidate == x)
continue;
if (get_bandit_at(candidate) != null)
continue;
return candidate;
}
@@ -158,7 +164,8 @@ int pick_bandit_spawn_position(int range_start, int range_end) {
int pick_bandit_spawn_east_of_player(int min_distance, int max_distance, int range_start, int range_end) {
int min_dist = min_distance;
int max_dist = max_distance;
if (min_dist < 0) min_dist = 0;
if (min_dist < 0)
min_dist = 0;
if (max_dist < min_dist) {
int temp = min_dist;
min_dist = max_dist;
@@ -176,10 +183,13 @@ int pick_bandit_spawn_east_of_player(int min_distance, int max_distance, int ran
range_end_norm = temp;
}
if (start < range_start_norm) start = range_start_norm;
if (end > range_end_norm) end = range_end_norm;
if (start < range_start_norm)
start = range_start_norm;
if (end > range_end_norm)
end = range_end_norm;
if (start > end) return -1;
if (start > end)
return -1;
return pick_bandit_spawn_position(start, end);
}
@@ -187,7 +197,8 @@ int pick_bandit_spawn_east_of_player(int min_distance, int max_distance, int ran
int pick_bandit_spawn_west_of_player(int min_distance, int max_distance, int range_start, int range_end) {
int min_dist = min_distance;
int max_dist = max_distance;
if (min_dist < 0) min_dist = 0;
if (min_dist < 0)
min_dist = 0;
if (max_dist < min_dist) {
int temp = min_dist;
min_dist = max_dist;
@@ -205,29 +216,38 @@ int pick_bandit_spawn_west_of_player(int min_distance, int max_distance, int ran
range_end_norm = temp;
}
if (start < range_start_norm) start = range_start_norm;
if (end > range_end_norm) end = range_end_norm;
if (start < range_start_norm)
start = range_start_norm;
if (end > range_end_norm)
end = range_end_norm;
if (start > end) return -1;
if (start > end)
return -1;
return pick_bandit_spawn_position(start, end);
}
int pick_bandit_spawn_near_player(int range_start, int range_end) {
// Preferred: 30-50 tiles east of player.
int spawn_x = pick_bandit_spawn_east_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1) return spawn_x;
int spawn_x =
pick_bandit_spawn_east_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1)
return spawn_x;
// Fallback: 30-50 tiles west when east side is not available.
spawn_x = pick_bandit_spawn_west_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1) return spawn_x;
spawn_x =
pick_bandit_spawn_west_of_player(BANDIT_SPAWN_MIN_DISTANCE, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1)
return spawn_x;
// If map bounds are tight, relax minimum distance but keep around player.
spawn_x = pick_bandit_spawn_east_of_player(1, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1) return spawn_x;
if (spawn_x != -1)
return spawn_x;
spawn_x = pick_bandit_spawn_west_of_player(1, BANDIT_SPAWN_MAX_DISTANCE, range_start, range_end);
if (spawn_x != -1) return spawn_x;
if (spawn_x != -1)
return spawn_x;
return -1;
}
@@ -250,7 +270,7 @@ int count_bandits_in_range(int range_start, int range_end) {
return count;
}
void spawn_bandit(int expansion_start, int expansion_end, const string&in invader_type = "bandit") {
void spawn_bandit(int expansion_start, int expansion_end, const string& in invader_type = "bandit") {
int spawn_x = -1;
if (invasion_active) {
spawn_x = pick_bandit_spawn_near_player(expansion_start, expansion_end);
@@ -258,7 +278,8 @@ void spawn_bandit(int expansion_start, int expansion_end, const string&in invade
if (spawn_x == -1) {
spawn_x = pick_bandit_spawn_position(expansion_start, expansion_end);
}
if (spawn_x == -1) return;
if (spawn_x == -1)
return;
int home_start = expansion_start;
int home_end = expansion_end;
@@ -271,7 +292,7 @@ void spawn_bandit(int expansion_start, int expansion_end, const string&in invade
}
}
Bandit@ b = Bandit(spawn_x, home_start, home_end, invader_type);
Bandit @b = Bandit(spawn_x, home_start, home_end, invader_type);
if (!invasion_active) {
b.behavior_state = "wandering";
}
@@ -285,7 +306,7 @@ void spawn_bandit(int expansion_start, int expansion_end, const string&in invade
}
}
bool can_bandit_attack_player(Bandit@ bandit) {
bool can_bandit_attack_player(Bandit @bandit) {
if (player_health <= 0) {
return false;
}
@@ -302,7 +323,7 @@ bool can_bandit_attack_player(Bandit@ bandit) {
return y <= BANDIT_ATTACK_MAX_HEIGHT;
}
bool try_attack_player_bandit(Bandit@ bandit) {
bool try_attack_player_bandit(Bandit @bandit) {
if (!can_bandit_attack_player(bandit)) {
return false;
}
@@ -336,16 +357,19 @@ bool try_attack_player_bandit(Bandit@ bandit) {
return true;
}
void try_attack_barricade_bandit(Bandit@ bandit) {
if (barricade_health <= 0) return;
if (bandit.attack_timer.elapsed < BANDIT_ATTACK_INTERVAL) return;
void try_attack_barricade_bandit(Bandit @bandit) {
if (barricade_health <= 0)
return;
if (bandit.attack_timer.elapsed < BANDIT_ATTACK_INTERVAL)
return;
bandit.attack_timer.restart();
// Bandits do 1-2 damage to barricade
int damage = random(BANDIT_DAMAGE_MIN, BANDIT_DAMAGE_MAX);
barricade_health -= damage;
if (barricade_health < 0) barricade_health = 0;
if (barricade_health < 0)
barricade_health = 0;
// Play weapon swing sound (barricade hits share a common impact sound)
if (bandit.weapon_type == "spear") {
@@ -372,7 +396,7 @@ void try_attack_barricade_bandit(Bandit@ bandit) {
}
}
void update_bandit(Bandit@ bandit, bool audio_active) {
void update_bandit(Bandit @bandit, bool audio_active) {
bool enforce_home = (!invasion_active && bandit.home_start <= bandit.home_end);
if (enforce_home) {
if (bandit.position < bandit.home_start) {
@@ -395,14 +419,16 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
if (bandit.sound_handle != -1) {
p.destroy_sound(bandit.sound_handle);
}
bandit.sound_handle = play_1d_with_volume_step(bandit.alert_sound, x, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
bandit.sound_handle =
play_1d_with_volume_step(bandit.alert_sound, x, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
}
if (try_attack_player_bandit(bandit)) {
return;
}
if (bandit.move_timer.elapsed < bandit.move_interval) return;
if (bandit.move_timer.elapsed < bandit.move_interval)
return;
bandit.move_timer.restart();
// If barricade is up and bandit is at the edge of base, attack barricade
@@ -423,7 +449,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
if (bandit.wander_direction_timer.elapsed > bandit.wander_direction_change_interval) {
// Time to change direction
bandit.wander_direction = random(-1, 1);
bandit.wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
bandit.wander_direction_change_interval =
random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
bandit.wander_direction_timer.restart();
}
@@ -444,7 +471,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
} else {
bandit.position = target_x;
if (audio_active) {
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END,
BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
}
}
} else {
@@ -479,7 +507,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
}
int target_x = bandit.position + direction;
if (target_x < 0 || target_x >= MAP_SIZE) return;
if (target_x < 0 || target_x >= MAP_SIZE)
return;
if (enforce_home && (target_x < bandit.home_start || target_x > bandit.home_end)) {
return;
@@ -493,7 +522,8 @@ void update_bandit(Bandit@ bandit, bool audio_active) {
bandit.position = target_x;
if (audio_active) {
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE, BANDIT_SOUND_VOLUME_STEP);
play_creature_footstep(x, bandit.position, BASE_END, GRASS_END, BANDIT_FOOTSTEP_MAX_DISTANCE,
BANDIT_SOUND_VOLUME_STEP);
}
}
}
@@ -506,7 +536,8 @@ void update_bandits() {
bool limit_audio = (areaStarts.length() > 0);
for (uint i = 0; i < bandits.length(); i++) {
bool audio_active = !limit_audio || range_overlaps_active_areas(bandits[i].position, bandits[i].position, areaStarts, areaEnds);
bool audio_active =
!limit_audio || range_overlaps_active_areas(bandits[i].position, bandits[i].position, areaStarts, areaEnds);
update_bandit(bandits[i], audio_active);
}
}
@@ -520,7 +551,8 @@ bool damage_bandit_at(int pos, int damage) {
p.destroy_sound(bandits[i].sound_handle);
bandits[i].sound_handle = -1;
}
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", bandits[i].alert_sound, x, pos, BANDIT_SOUND_VOLUME_STEP);
play_creature_death_sounds("sounds/enemies/enemy_falls.ogg", bandits[i].alert_sound, x, pos,
BANDIT_SOUND_VOLUME_STEP);
bandits.remove_at(i);
}
return true;
+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;
+65 -38
View File
@@ -15,7 +15,7 @@ class GroundGame {
int area_start;
int area_end;
int wander_direction; // -1, 0, 1
string animal_type; // "boar", future: "mountain_goat", "ram", etc.
string animal_type; // "boar", future: "mountain_goat", "ram", etc.
bool in_weapon_range;
GroundGame(int pos, int start, int end, string type = "boar") {
@@ -36,8 +36,7 @@ class GroundGame {
next_move_delay = random(BOAR_MOVE_INTERVAL_MIN, BOAR_MOVE_INTERVAL_MAX);
in_weapon_range = false;
}
}
GroundGame@[] ground_games;
} GroundGame @[] ground_games;
void update_ground_game_weapon_range_audio() {
for (uint i = 0; i < ground_games.length(); i++) {
@@ -47,12 +46,14 @@ void update_ground_game_weapon_range_audio() {
bool ground_game_range_audio_registered = false;
void ensure_ground_game_range_audio_registration() {
if (ground_game_range_audio_registered) return;
if (ground_game_range_audio_registered)
return;
ground_game_range_audio_registered = register_weapon_range_audio_callback(@update_ground_game_weapon_range_audio);
}
void clear_ground_games() {
if (ground_games.length() == 0) return;
if (ground_games.length() == 0)
return;
for (uint i = 0; i < ground_games.length(); i++) {
force_weapon_range_exit(ground_games[i].position, ground_games[i].in_weapon_range);
@@ -64,7 +65,7 @@ void clear_ground_games() {
ground_games.resize(0);
}
GroundGame@ get_ground_game_at(int pos) {
GroundGame @get_ground_game_at(int pos) {
for (uint i = 0; i < ground_games.length(); i++) {
if (ground_games[i].position == pos) {
return @ground_games[i];
@@ -80,16 +81,18 @@ void spawn_ground_game(int expansion_start, int expansion_end) {
int candidate = random(expansion_start, expansion_end);
// Don't spawn too close to base (keep away from BASE_END)
if (candidate <= BASE_END + 5) continue;
if (candidate <= BASE_END + 5)
continue;
if (get_ground_game_at(candidate) == null) {
spawn_x = candidate;
break;
}
}
if (spawn_x == -1) return; // Failed to find spot
if (spawn_x == -1)
return; // Failed to find spot
GroundGame@ b = GroundGame(spawn_x, expansion_start, expansion_end, "boar");
GroundGame @b = GroundGame(spawn_x, expansion_start, expansion_end, "boar");
ground_games.insert_last(b);
// Play looping sound that follows the boar
int[] areaStarts;
@@ -100,34 +103,40 @@ void spawn_ground_game(int expansion_start, int expansion_end) {
}
}
bool can_ground_game_attack_player(GroundGame@ game) {
if (player_health <= 0) return false;
bool can_ground_game_attack_player(GroundGame @game) {
if (player_health <= 0)
return false;
// Check if player is on ground (ground game can't fly/climb)
if (y > 0) return false;
if (y > 0)
return false;
if (abs(game.position - x) > 1) return false;
if (abs(game.position - x) > 1)
return false;
return true;
}
bool try_attack_player_ground_game(GroundGame@ game) {
if (!can_ground_game_attack_player(game)) return false;
bool try_attack_player_ground_game(GroundGame @game) {
if (!can_ground_game_attack_player(game))
return false;
if (game.attack_timer.elapsed < BOAR_ATTACK_INTERVAL) return false;
if (game.attack_timer.elapsed < BOAR_ATTACK_INTERVAL)
return false;
game.attack_timer.restart();
// Attack!
int damage = random(BOAR_DAMAGE_MIN, BOAR_DAMAGE_MAX);
player_health -= damage;
if (player_health < 0) player_health = 0;
if (player_health < 0)
player_health = 0;
play_player_damage_sound();
return true;
}
void update_ground_game(GroundGame@ game, bool audio_active) {
void update_ground_game(GroundGame @game, bool audio_active) {
// Update looping sound position
if (!audio_active) {
if (game.sound_handle != -1) {
@@ -152,7 +161,8 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
// Movement logic
int move_speed = (game.state == "charging") ? BOAR_CHARGE_SPEED : game.next_move_delay;
if (game.move_timer.elapsed < move_speed) return;
if (game.move_timer.elapsed < move_speed)
return;
game.move_timer.restart();
if (game.state == "wandering") {
game.next_move_delay = random(BOAR_MOVE_INTERVAL_MIN, BOAR_MOVE_INTERVAL_MAX);
@@ -175,10 +185,11 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
// Don't leave area or enter base
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
game.position = target;
if (audio_active) {
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
}
game.position = target;
if (audio_active) {
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE,
BOAR_SOUND_VOLUME_STEP);
}
}
} else {
// Wandering
@@ -188,12 +199,13 @@ void update_ground_game(GroundGame@ game, bool audio_active) {
if (game.wander_direction != 0) {
int target = game.position + game.wander_direction;
// Don't leave area or enter base
// Don't leave area or enter base
if (target >= game.area_start && target <= game.area_end && target > BASE_END) {
game.position = target;
if (audio_active) {
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE, BOAR_SOUND_VOLUME_STEP);
}
game.position = target;
if (audio_active) {
play_creature_footstep(x, game.position, BASE_END, GRASS_END, BOAR_FOOTSTEP_MAX_DISTANCE,
BOAR_SOUND_VOLUME_STEP);
}
} else {
game.wander_direction = -game.wander_direction; // Turn around
}
@@ -209,14 +221,17 @@ void update_ground_games() {
bool limit_audio = (areaStarts.length() > 0);
for (uint i = 0; i < ground_games.length(); i++) {
bool audio_active = !limit_audio || range_overlaps_active_areas(ground_games[i].position, ground_games[i].position, areaStarts, areaEnds);
bool audio_active = !limit_audio || range_overlaps_active_areas(ground_games[i].position,
ground_games[i].position, areaStarts, areaEnds);
update_ground_game(ground_games[i], audio_active);
}
}
void attempt_hourly_ground_game_spawn() {
if (expanded_area_start == -1) return;
if (ground_games.length() >= BOAR_MAX_COUNT) return;
if (expanded_area_start == -1)
return;
if (ground_games.length() >= BOAR_MAX_COUNT)
return;
if (random(1, 100) <= BOAR_SPAWN_CHANCE_PER_HOUR) {
spawn_ground_game(expanded_area_start, expanded_area_end);
@@ -246,10 +261,22 @@ bool damage_ground_game_at(int pos, int damage) {
}
// Backward compatibility aliases (to be removed after refactoring)
GroundGame@[]@ boars = @ground_games;
GroundGame@ get_boar_at(int pos) { return get_ground_game_at(pos); }
void clear_boars() { clear_ground_games(); }
void spawn_boar(int expansion_start, int expansion_end) { spawn_ground_game(expansion_start, expansion_end); }
void update_boars() { update_ground_games(); }
void attempt_hourly_boar_spawn() { attempt_hourly_ground_game_spawn(); }
bool damage_boar_at(int pos, int damage) { return damage_ground_game_at(pos, damage); }
GroundGame @[] @boars = @ground_games;
GroundGame @get_boar_at(int pos) {
return get_ground_game_at(pos);
}
void clear_boars() {
clear_ground_games();
}
void spawn_boar(int expansion_start, int expansion_end) {
spawn_ground_game(expansion_start, expansion_end);
}
void update_boars() {
update_ground_games();
}
void attempt_hourly_boar_spawn() {
attempt_hourly_ground_game_spawn();
}
bool damage_boar_at(int pos, int damage) {
return damage_ground_game_at(pos, damage);
}
+131 -77
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");
}
+140 -112
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,34 +559,34 @@ Tree@ get_tree_at(int target_x) {
}
void damage_tree(int target_x, int damage) {
Tree@ target = null;
for(uint i=0; i<trees.length(); i++) {
if(trees[i].position == target_x) {
Tree @target = null;
for (uint i = 0; i < trees.length(); i++) {
if (trees[i].position == target_x) {
@target = @trees[i];
break;
}
}
if(@target != null) {
if(!target.is_chopped) {
if (@target != null) {
if (!target.is_chopped) {
target.health -= damage;
p.play_stationary("sounds/weapons/axe_hit.ogg", false);
if(target.health <= 0) {
if (target.health <= 0) {
target.is_chopped = true;
target.depleted = true;
target.regen_timer.restart();
target.minutes_since_depletion = 0;
// Stop the looping sound
if (target.sound_handle != -1) {
p.destroy_sound(target.sound_handle);
target.sound_handle = -1;
}
// Play the falling sound at the tree's position
p.play_1d("sounds/items/tree.ogg", x, target.position, false);
int sticks_dropped = random(1, 3);
int vines_dropped = random(1, 2);
int sticks_added = add_to_stack(get_personal_count(ITEM_STICKS), sticks_dropped);
@@ -578,7 +599,8 @@ void damage_tree(int target_x, int damage) {
string drop_message = "Tree fell!";
if (sticks_added > 0 || vines_added > 0 || logs_added > 0) {
string log_label = (logs_added == 1) ? " log" : " logs";
drop_message += " Got " + sticks_added + " sticks, " + vines_added + " vines, and " + logs_added + log_label + ".";
drop_message += " Got " + sticks_added + " sticks, " + vines_added + " vines, and " + logs_added +
log_label + ".";
}
if (sticks_added < sticks_dropped || vines_added < vines_dropped || logs_added < 1) {
drop_message += " Inventory full.";
@@ -626,7 +648,8 @@ string get_auto_found_message(int item_type) {
}
string first_letter = singular.substr(0, 1);
if (first_letter == "a" || first_letter == "e" || first_letter == "i" || first_letter == "o" || first_letter == "u") {
if (first_letter == "a" || first_letter == "e" || first_letter == "i" || first_letter == "o" ||
first_letter == "u") {
return "Found an " + singular + ".";
}
return "Found a " + singular + ".";
@@ -698,19 +721,18 @@ bool try_search_for_terrain(string terrain_type) {
}
for (uint j = 0; j < search_pools[i].terrain_tags.length(); j++) {
if (search_pools[i].terrain_tags[j] == terrain_type) {
return try_find_weighted_resource(search_pools[i].item_types,
search_pools[i].weights, search_pools[i].found_messages);
return try_find_weighted_resource(search_pools[i].item_types, search_pools[i].weights,
search_pools[i].found_messages);
}
}
}
return false;
}
void perform_search(int current_x)
{
void perform_search(int current_x) {
// First priority: Check for world drops on this tile or adjacent
for (int check_x = current_x - 1; check_x <= current_x + 1; check_x++) {
WorldDrop@ drop = get_drop_at(check_x);
WorldDrop @drop = get_drop_at(check_x);
if (drop != null) {
if (!try_pickup_world_drop(drop)) {
return;
@@ -723,15 +745,16 @@ void perform_search(int current_x)
// Check for snares nearby (adjacent within range)
for (int check_x = current_x - SNARE_COLLECT_RANGE; check_x <= current_x + SNARE_COLLECT_RANGE; check_x++) {
// Skip current x? User said "beside". If on top, it breaks.
// Skip current x? User said "beside". If on top, it breaks.
// But if I stand adjacent and shift...
if (check_x == current_x) continue; // Safety against collecting own snare you stand on? (Collision happens on move)
if (check_x == current_x)
continue; // Safety against collecting own snare you stand on? (Collision happens on move)
// Actually, collision happens when *moving onto* it. If you placed it, you are on it.
// If active is false (just placed), you can pick it up.
// If active is true (you moved away), moving back breaks it.
// So checking adjacent is correct.
WorldSnare@ s = get_snare_at(check_x);
WorldSnare @s = get_snare_at(check_x);
if (s != null) {
if (s.has_catch) {
if (get_personal_count(ITEM_SMALL_GAME) >= get_personal_stack_limit()) {
@@ -791,7 +814,8 @@ void perform_search(int current_x)
break;
}
}
if (near_stream_bank) break;
if (near_stream_bank)
break;
}
}
@@ -803,17 +827,15 @@ void perform_search(int current_x)
// Trees (Sticks/Vines) - Check for nearby tree, but only on non-stone terrain
// Skip tree search if player is on stone terrain (prioritize stone finding)
string search_terrain = get_terrain_at_position(current_x);
bool skip_tree_search = (search_terrain == "stone" || search_terrain == "gravel" ||
search_terrain == "snow" || search_terrain == "hard_stone");
bool skip_tree_search = (search_terrain == "stone" || search_terrain == "gravel" || search_terrain == "snow" ||
search_terrain == "hard_stone");
Tree@ nearest = null;
Tree @nearest = null;
int nearest_distance = 999;
if (!skip_tree_search) {
for(uint i=0; i<trees.length(); i++)
{
for (uint i = 0; i < trees.length(); i++) {
int distance = abs(trees[i].position - current_x);
if(distance <= 1 && distance < nearest_distance)
{
if (distance <= 1 && distance < nearest_distance) {
nearest_distance = distance;
@nearest = @trees[i];
if (nearest_distance == 0) {
@@ -823,20 +845,18 @@ void perform_search(int current_x)
}
}
if(@nearest != null)
{
if(nearest.is_chopped) {
if (@nearest != null) {
if (nearest.is_chopped) {
speak_with_history("This tree has been cut down.", true);
return;
}
if (nearest.depleted) {
speak_with_history("This tree is empty.", true);
return;
speak_with_history("This tree is empty.", true);
return;
}
if(nearest.sticks > 0 || nearest.vines > 0)
{
if (nearest.sticks > 0 || nearest.vines > 0) {
bool find_stick = (nearest.vines <= 0) || (nearest.sticks > 0 && random(0, 1) == 0);
bool took_item = false;
@@ -880,15 +900,13 @@ void perform_search(int current_x)
}
return;
}
if(nearest.sticks == 0 && nearest.vines == 0) {
if (nearest.sticks == 0 && nearest.vines == 0) {
nearest.depleted = true;
nearest.regen_timer.restart();
nearest.minutes_since_depletion = 0;
}
}
else
{
} else {
speak_with_history("This area has nothing left.", true);
}
return;
@@ -903,7 +921,7 @@ void perform_search(int current_x)
// Climbing functions
void start_climbing_tree(int target_x) {
Tree@ tree = get_tree_at(target_x);
Tree @tree = get_tree_at(target_x);
if (tree == null || tree.is_chopped) {
return;
}
@@ -916,7 +934,8 @@ void start_climbing_tree(int target_x) {
}
void update_climbing() {
if (!climbing) return;
if (!climbing)
return;
if (y == climb_target_y) {
climbing = false;
return;
@@ -955,7 +974,8 @@ void update_climbing() {
void climb_down_tree() {
int ground_elevation = get_mountain_elevation_at(x);
if (y == ground_elevation || climbing) return;
if (y == ground_elevation || climbing)
return;
climbing = true;
climb_target_y = ground_elevation;
@@ -964,7 +984,8 @@ void climb_down_tree() {
}
void start_falling() {
if (y <= 0 || falling) return;
if (y <= 0 || falling)
return;
falling = true;
fall_start_y = y; // Remember where we started falling from
@@ -975,7 +996,8 @@ void start_falling() {
}
void update_falling() {
if (!falling) return;
if (!falling)
return;
// Get ground level (mountain elevation or 0)
int ground_level = get_mountain_elevation_at(x);
@@ -995,8 +1017,10 @@ void update_falling() {
// Pitch ranges from 100 (high up) to 50 (near ground)
float height_above_ground = float(y - ground_level);
float pitch_percent = 50.0 + (50.0 * (height_above_ground / 30.0));
if (pitch_percent < 50.0) pitch_percent = 50.0;
if (pitch_percent > 100.0) pitch_percent = 100.0;
if (pitch_percent < 50.0)
pitch_percent = 50.0;
if (pitch_percent > 100.0)
pitch_percent = 100.0;
fall_sound_handle = p.play_stationary_extended("sounds/actions/falling.ogg", true, 0, 0, 0, pitch_percent);
@@ -1028,7 +1052,7 @@ void land_on_ground(int ground_level) {
// Mountain movement check
bool can_move_mountain(int from_x, int to_x) {
MountainRange@ mountain = get_mountain_at(to_x);
MountainRange @mountain = get_mountain_at(to_x);
if (mountain is null) {
// Not entering a mountain
return true;
@@ -1066,8 +1090,10 @@ bool can_move_mountain(int from_x, int to_x) {
}
bool can_enter_stream_tile(int pos) {
if (!is_deep_stream_at(pos)) return true;
if (get_personal_count(ITEM_CANOES) > 0) return true;
if (!is_deep_stream_at(pos))
return true;
if (get_personal_count(ITEM_CANOES) > 0)
return true;
speak_movement_blocked("You need a canoe to cross deep water.");
return false;
}
@@ -1116,7 +1142,8 @@ void start_rope_climb(bool climbing_up, int target_x, int target_elevation) {
}
void update_rope_climbing() {
if (!rope_climbing) return;
if (!rope_climbing)
return;
// Check if we're already at the target (shouldn't happen, but safety check)
if (y == rope_climb_target_y) {
@@ -1168,7 +1195,8 @@ void complete_rope_climb() {
}
void check_rope_climb_fall() {
if (!rope_climbing) return;
if (!rope_climbing)
return;
if (key_down(KEY_LEFT) || key_down(KEY_RIGHT)) {
rope_climb_sound_handle = -1;
+67 -36
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() {