A few bug fixes. Part of major refactor.

This commit is contained in:
Storm Dragon
2026-01-21 18:14:26 -05:00
parent 129cd4a656
commit af9a402e80
18 changed files with 660 additions and 433 deletions

View File

@@ -19,15 +19,16 @@ sound_pool p(100);
#include "src/audio_utils.nvgt"
#include "src/creature_audio.nvgt"
#include "src/notify.nvgt"
#include "src/speech_history.nvgt"
int run_main_menu() {
screen_reader_speak("Draugnorak. Main menu.", true);
speak_with_history("Draugnorak. Main menu.", true);
int selection = 0;
string load_label = has_save_game() ? "Load Game" : "Load Game (no save found)";
string[] options = {"New Game", load_label, "Exit"};
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
while(true) {
wait(5);
@@ -35,13 +36,13 @@ int run_main_menu() {
if (key_pressed(KEY_DOWN)) {
selection++;
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
selection--;
if (selection < 0) selection = options.length() - 1;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
@@ -78,11 +79,11 @@ void main()
}
}
start_new_game();
screen_reader_speak("New game started.", true);
speak_with_history("New game started.", true);
game_started = true;
} else if (selection == 1) {
if (load_game_state()) {
screen_reader_speak("Game loaded.", true);
speak_with_history("Game loaded.", true);
game_started = true;
} else {
if (has_save_game()) {
@@ -108,10 +109,10 @@ void main()
game_paused = !game_paused;
if (game_paused) {
p.pause_all();
screen_reader_speak("Paused. Press backspace to resume.", true);
speak_with_history("Paused. Press backspace to resume.", true);
} else {
p.resume_all();
screen_reader_speak("Resumed.", true);
speak_with_history("Resumed.", true);
}
continue;
}
@@ -150,7 +151,7 @@ void main()
if (fire_on_tile != null && !jumping && fire_damage_timer.elapsed > 1000) {
player_health--;
fire_damage_timer.restart();
screen_reader_speak("Burning! " + player_health + " health remaining.", true);
speak_with_history("Burning! " + player_health + " health remaining.", true);
}
// Healing in base area
@@ -161,13 +162,13 @@ void main()
if (healing_timer.elapsed > heal_interval) {
player_health++;
healing_timer.restart();
screen_reader_speak(player_health + " health.", true);
speak_with_history(player_health + " health.", true);
}
}
// Death check
if (player_health <= 0) {
screen_reader_speak("You have died.", true);
speak_with_history("You have died.", true);
wait(2000);
exit();
}
@@ -182,21 +183,17 @@ void main()
check_quick_slot_keys();
check_time_input();
check_notification_keys();
check_speech_history_keys();
// Health Key
if (key_pressed(KEY_H)) {
screen_reader_speak(player_health + " health of " + max_health, true);
speak_with_history(player_health + " health of " + max_health, true);
}
// Coordinates Key
if (key_pressed(KEY_X)) {
string direction_label = (facing == 1) ? "east" : "west";
string terrain_info = "";
MountainRange@ mountain = get_mountain_at(x);
if (mountain !is null) {
terrain_info = ", elevation " + y + ", " + mountain.get_terrain_at(x);
}
screen_reader_speak(direction_label + ", x " + x + ", y " + y + terrain_info, true);
speak_with_history(direction_label + ", x " + x + ", y " + y, true);
}
// Base Info Key (base only)
@@ -243,13 +240,16 @@ void main()
}
else if(!jumping && !climbing && !falling && !rope_climbing)
{
// Get ground elevation at current position
int ground_elevation = get_mountain_elevation_at(x);
// Check if on tree tile
Tree@ tree = get_tree_at(x);
if (tree != null && !tree.is_chopped && y == 0) {
if (tree != null && !tree.is_chopped && y == ground_elevation) {
// Start climbing the tree
start_climbing_tree(x);
} else if (y == 0) {
// Normal jump
} else if (y == ground_elevation) {
// Normal jump (only if on the ground)
p.play_stationary("sounds/jump.ogg", false);
jumping = true;
jumptimer.restart();
@@ -260,15 +260,16 @@ void main()
if(jumping && jumptimer.elapsed > 850)
{
jumping = false;
y = 0; // Reset y after jump
// Reset y to ground elevation after jump
y = get_mountain_elevation_at(x);
play_land_sound(x, BASE_END, GRASS_END);
// Check for snare on landing?
check_snare_collision(x);
}
// Set y to 3 during jump
if(jumping && y == 0) {
y = 3;
// Set y to 3 above ground during jump
if(jumping && y == get_mountain_elevation_at(x)) {
y = get_mountain_elevation_at(x) + 3;
}
movetime = jumping ? jump_speed : walk_speed;
@@ -276,14 +277,14 @@ void main()
// Movement Logic
if (key_pressed(KEY_LEFT) && facing != 0 && !climbing && !falling && !rope_climbing) {
facing = 0;
screen_reader_speak("west", true);
speak_with_history("west", true);
walktimer.restart();
// Cancel pending rope climb when changing direction
pending_rope_climb_x = -1;
}
if (key_pressed(KEY_RIGHT) && facing != 1 && !climbing && !falling && !rope_climbing) {
facing = 1;
screen_reader_speak("east", true);
speak_with_history("east", true);
walktimer.restart();
// Cancel pending rope climb when changing direction
pending_rope_climb_x = -1;
@@ -295,7 +296,9 @@ void main()
// Check if trying to move left/right while in tree (not in mountain)
MountainRange@ current_mountain = get_mountain_at(x);
if((key_down(KEY_LEFT) || key_down(KEY_RIGHT)) && y > 0 && !jumping && !falling && !rope_climbing && current_mountain is null) {
Tree@ current_tree = get_tree_at(x);
int ground_elevation = get_mountain_elevation_at(x);
if((key_down(KEY_LEFT) || key_down(KEY_RIGHT)) && y > ground_elevation && !jumping && !falling && !rope_climbing && current_mountain is null && current_tree !is null) {
// Fall out of tree
climbing = false;
start_falling();
@@ -307,9 +310,9 @@ void main()
// Check mountain movement
if (can_move_mountain(x, x - 1)) {
x--;
// Update elevation if in mountain
// Always update elevation to match ground (0 if not in mountain)
int new_elevation = get_mountain_elevation_at(x);
if (new_elevation != y && get_mountain_at(x) !is null) {
if (new_elevation != y) {
y = new_elevation;
}
walktimer.restart();
@@ -325,9 +328,9 @@ void main()
// Check mountain movement
if (can_move_mountain(x, x + 1)) {
x++;
// Update elevation if in mountain
// Always update elevation to match ground (0 if not in mountain)
int new_elevation = get_mountain_elevation_at(x);
if (new_elevation != y && get_mountain_at(x) !is null) {
if (new_elevation != y) {
y = new_elevation;
}
walktimer.restart();
@@ -377,7 +380,7 @@ void main()
sling_sound_handle = p.play_stationary("sounds/weapons/sling_swing.ogg", true);
last_sling_stage = -1;
} else {
screen_reader_speak("No stones.", true);
speak_with_history("No stones.", true);
}
}

View File

@@ -255,7 +255,7 @@ void attempt_resident_collection() {
// Announce only if player is in base
if (x <= BASE_END) {
screen_reader_speak("Resident added " + item_name + " to storage.", true);
speak_with_history("Resident added " + item_name + " to storage.", true);
}
}
}

View File

@@ -134,7 +134,7 @@ void release_sling_attack(int player_x) {
// Only hit if released during in-range window (stage 1)
if (stage != 1) {
screen_reader_speak("Stone missed.", true);
speak_with_history("Stone missed.", true);
return;
}
@@ -192,7 +192,7 @@ void release_sling_attack(int player_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);
screen_reader_speak("Stone hit tree at " + check_x + ".", true);
speak_with_history("Stone hit tree at " + check_x + ".", true);
return;
}
}
@@ -200,7 +200,7 @@ void release_sling_attack(int player_x) {
// No target found
if (target_x == -1) {
screen_reader_speak("Stone missed.", true);
speak_with_history("Stone missed.", true);
return;
}

View File

@@ -2,6 +2,7 @@
int MAP_SIZE = 35;
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
// Expansion configuration
@@ -149,7 +150,7 @@ const float FLYING_CREATURE_FADE_OUT_MIN_VOLUME = -40.0; // dB
const int MOUNTAIN_SIZE = 60;
const int MOUNTAIN_MIN_ELEVATION = 0;
const int MOUNTAIN_MAX_ELEVATION = 40;
const int MOUNTAIN_STEEP_THRESHOLD = 6;
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;

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ void apply_falling_damage(int fall_height) {
p.play_stationary("sounds/actions/hit_ground.ogg", false);
if (fall_height <= SAFE_FALL_HEIGHT) {
screen_reader_speak("Landed safely.", true);
speak_with_history("Landed safely.", true);
return;
}
@@ -23,7 +23,7 @@ void apply_falling_damage(int fall_height) {
if (player_health < 0) player_health = 0;
// Feedback
screen_reader_speak("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 {
@@ -439,7 +439,7 @@ void damage_tree(int target_x, int damage) {
}
p.play_stationary("sounds/items/stick.ogg", false);
screen_reader_speak(drop_message, true);
speak_with_history(drop_message, true);
}
}
}
@@ -474,24 +474,24 @@ void perform_search(int current_x)
if (s != null) {
if (s.has_catch) {
if (inv_small_game >= get_personal_stack_limit()) {
screen_reader_speak("You can't carry any more small game.", true);
speak_with_history("You can't carry any more small game.", true);
return;
}
if (inv_snares >= get_personal_stack_limit()) {
screen_reader_speak("You can't carry any more snares.", true);
speak_with_history("You can't carry any more snares.", true);
return;
}
inv_small_game++;
inv_small_game_types.insert_last(s.catch_type);
inv_snares++; // Recover snare
screen_reader_speak("Collected " + s.catch_type + " and snare.", true);
speak_with_history("Collected " + s.catch_type + " and snare.", true);
} else {
if (inv_snares >= get_personal_stack_limit()) {
screen_reader_speak("You can't carry any more snares.", true);
speak_with_history("You can't carry any more snares.", true);
return;
}
inv_snares++; // Recover snare
screen_reader_speak("Collected snare.", true);
speak_with_history("Collected snare.", true);
}
p.play_stationary("sounds/items/miscellaneous.ogg", false);
remove_snare_at(check_x);
@@ -500,7 +500,7 @@ void perform_search(int current_x)
}
if (random(1, 100) <= 10) {
screen_reader_speak("Found nothing.", true);
speak_with_history("Found nothing.", true);
return;
}
@@ -525,14 +525,14 @@ void perform_search(int current_x)
if (inv_reeds < get_personal_stack_limit()) {
inv_reeds++;
p.play_stationary("sounds/items/stick.ogg", false);
screen_reader_speak("Found a reed.", true);
speak_with_history("Found a reed.", true);
return;
}
} else {
if (inv_clay < get_personal_stack_limit()) {
inv_clay++;
p.play_stationary("sounds/items/clay.ogg", false);
screen_reader_speak("Found clay.", true);
speak_with_history("Found clay.", true);
return;
}
}
@@ -540,15 +540,15 @@ void perform_search(int current_x)
if (!found_reed && inv_reeds < get_personal_stack_limit()) {
inv_reeds++;
p.play_stationary("sounds/items/stick.ogg", false);
screen_reader_speak("Found a reed.", true);
speak_with_history("Found a reed.", true);
} else if (found_reed && inv_clay < get_personal_stack_limit()) {
inv_clay++;
p.play_stationary("sounds/items/clay.ogg", false);
screen_reader_speak("Found clay.", true);
speak_with_history("Found clay.", true);
} else if (found_reed) {
screen_reader_speak("You can't carry any more reeds.", true);
speak_with_history("You can't carry any more reeds.", true);
} else {
screen_reader_speak("You can't carry any more clay.", true);
speak_with_history("You can't carry any more clay.", true);
}
return;
}
@@ -573,12 +573,12 @@ void perform_search(int current_x)
if(@nearest != null)
{
if(nearest.is_chopped) {
screen_reader_speak("This tree has been cut down.", true);
speak_with_history("This tree has been cut down.", true);
return;
}
if (nearest.depleted) {
screen_reader_speak("This tree is empty.", true);
speak_with_history("This tree is empty.", true);
return;
}
@@ -592,13 +592,13 @@ void perform_search(int current_x)
nearest.sticks--;
inv_sticks++;
p.play_stationary("sounds/items/stick.ogg", false);
screen_reader_speak("Found a stick.", true);
speak_with_history("Found a stick.", true);
took_item = true;
} else if (nearest.vines > 0 && inv_vines < get_personal_stack_limit()) {
nearest.vines--;
inv_vines++;
p.play_stationary("sounds/items/vine.ogg", false);
screen_reader_speak("Found a vine.", true);
speak_with_history("Found a vine.", true);
took_item = true;
}
} else {
@@ -606,24 +606,24 @@ void perform_search(int current_x)
nearest.vines--;
inv_vines++;
p.play_stationary("sounds/items/vine.ogg", false);
screen_reader_speak("Found a vine.", true);
speak_with_history("Found a vine.", true);
took_item = true;
} else if (nearest.sticks > 0 && inv_sticks < get_personal_stack_limit()) {
nearest.sticks--;
inv_sticks++;
p.play_stationary("sounds/items/stick.ogg", false);
screen_reader_speak("Found a stick.", true);
speak_with_history("Found a stick.", true);
took_item = true;
}
}
if (!took_item) {
if (nearest.sticks > 0 && nearest.vines > 0) {
screen_reader_speak("You can't carry any more sticks or vines.", true);
speak_with_history("You can't carry any more sticks or vines.", true);
} else if (nearest.sticks > 0) {
screen_reader_speak("You can't carry any more sticks.", true);
speak_with_history("You can't carry any more sticks.", true);
} else {
screen_reader_speak("You can't carry any more vines.", true);
speak_with_history("You can't carry any more vines.", true);
}
return;
}
@@ -636,27 +636,58 @@ void perform_search(int current_x)
}
else
{
screen_reader_speak("This area has nothing left.", true);
speak_with_history("This area has nothing left.", true);
}
return;
}
// Gravel Area - Stones (20-34)
if (current_x >= 20 && current_x <= 34)
// Stone terrain - check for stones
bool is_stone_terrain = false;
// Check base gravel area (20-34)
if (current_x >= GRAVEL_START && current_x <= GRAVEL_END) {
is_stone_terrain = true;
}
// Check expanded areas
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);
if (mountain !is null) {
string terrain = mountain.get_terrain_at(current_x);
if (terrain == "stone" || terrain == "hard_stone") {
is_stone_terrain = true;
}
} else {
// Regular expanded area - check terrain type
int index = current_x - expanded_area_start;
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) {
terrain = terrain.substr(9);
}
if (terrain == "stone" || terrain == "hard_stone") {
is_stone_terrain = true;
}
}
}
}
if (is_stone_terrain)
{
if (inv_stones < get_personal_stack_limit())
{
inv_stones++;
p.play_stationary("sounds/items/stone.ogg", false);
screen_reader_speak("Found a stone.", true);
speak_with_history("Found a stone.", true);
}
else
{
screen_reader_speak("You can't carry any more stones.", true);
speak_with_history("You can't carry any more stones.", true);
}
return;
}
screen_reader_speak("Found nothing.", true);
speak_with_history("Found nothing.", true);
}
// Climbing functions
@@ -669,7 +700,7 @@ void start_climbing_tree(int target_x) {
climbing = true;
climb_target_y = tree.height;
climb_timer.restart();
screen_reader_speak("Started climbing tree. Height is " + tree.height + " feet.", true);
speak_with_history("Started climbing tree. Height is " + tree.height + " feet.", true);
}
void update_climbing() {
@@ -686,7 +717,7 @@ void update_climbing() {
if (y >= climb_target_y) {
climbing = false;
screen_reader_speak("Reached the top at " + y + " feet.", true);
speak_with_history("Reached the top at " + y + " feet.", true);
}
}
// Climbing down
@@ -697,7 +728,7 @@ void update_climbing() {
if (y <= 0) {
climbing = false;
y = 0;
screen_reader_speak("Safely reached the ground.", true);
speak_with_history("Safely reached the ground.", true);
}
}
}
@@ -709,7 +740,7 @@ void climb_down_tree() {
climbing = true;
climb_target_y = 0;
climb_timer.restart();
screen_reader_speak("Climbing down.", true);
speak_with_history("Climbing down.", true);
}
void start_falling() {
@@ -793,16 +824,16 @@ bool can_move_mountain(int from_x, int to_x) {
if (mountain.is_steep_section(from_x, to_x)) {
// Need rope
if (inv_ropes < 1) {
screen_reader_speak("You'll need a rope to climb there.", true);
speak_with_history("You'll need a rope to climb there.", true);
return false;
}
// Prompt for rope climb
int elevation_change = mountain.get_elevation_change(from_x, to_x);
if (elevation_change > 0) {
screen_reader_speak("Press up to climb up.", true);
speak_with_history("Press up to climb up.", true);
} else {
screen_reader_speak("Press down to climb down.", true);
speak_with_history("Press down to climb down.", true);
}
// Store pending rope climb info
@@ -817,22 +848,40 @@ bool can_move_mountain(int from_x, int to_x) {
// Rope climbing functions
void start_rope_climb(bool climbing_up, int target_x, int target_elevation) {
rope_climbing = true;
rope_climb_up = climbing_up;
rope_climb_target_x = target_x;
rope_climb_target_y = target_elevation;
rope_climb_start_y = y;
rope_climb_timer.restart();
int distance = rope_climb_target_y - y;
// Determine actual climbing direction based on elevation difference
int elevation_diff = target_elevation - y;
if (elevation_diff > 0) {
rope_climb_up = true;
} else if (elevation_diff < 0) {
rope_climb_up = false;
} else {
// Already at target elevation, no climbing needed
rope_climbing = false;
return;
}
// Calculate distance to climb (use actual distance from current position)
int distance = elevation_diff;
if (distance < 0) distance = -distance;
string direction = climbing_up ? "up" : "down";
screen_reader_speak("Climbing " + direction + ". " + distance + " feet.", true);
string direction = rope_climb_up ? "up" : "down";
speak_with_history("Climbing " + direction + ". " + distance + " feet.", true);
}
void update_rope_climbing() {
if (!rope_climbing) return;
// Check if we're already at the target (shouldn't happen, but safety check)
if (y == rope_climb_target_y) {
complete_rope_climb();
return;
}
// Climb at ROPE_CLIMB_SPEED ms per foot
if (rope_climb_timer.elapsed > ROPE_CLIMB_SPEED) {
rope_climb_timer.restart();
@@ -841,20 +890,24 @@ void update_rope_climbing() {
// Climbing up
if (y < rope_climb_target_y) {
y++;
p.play_stationary("sounds/actions/climb_rope.ogg", false);
// Check if we've reached the target BEFORE playing the sound
if (y >= rope_climb_target_y) {
complete_rope_climb();
} else {
p.play_stationary("sounds/actions/climb_rope.ogg", false);
}
}
} else {
// Climbing down
if (y > rope_climb_target_y) {
y--;
p.play_stationary("sounds/actions/climb_rope.ogg", false);
// Check if we've reached the target BEFORE playing the sound
if (y <= rope_climb_target_y) {
complete_rope_climb();
} else {
p.play_stationary("sounds/actions/climb_rope.ogg", false);
}
}
}
@@ -869,7 +922,7 @@ void complete_rope_climb() {
// Play footstep for new terrain
play_footstep(x, BASE_END, GRASS_END);
screen_reader_speak("Reached elevation " + y + ".", true);
speak_with_history("Reached elevation " + y + ".", true);
}
void check_rope_climb_fall() {

View File

@@ -67,5 +67,5 @@
// inv_meat++;
// inv_feathers += random(2, 4);
// inv_down += random(1, 2);
// screen_reader_speak("Butchered duck. Got 1 meat, feathers, and down.", true);
// speak_with_history("Butchered duck. Got 1 meat, feathers, and down.", true);
// }

View File

@@ -277,18 +277,18 @@ void activate_quick_slot(int slot_index) {
int equip_type = quick_slots[slot_index];
if (equip_type < 0) {
screen_reader_speak("No item bound to slot " + slot_index + ".", true);
speak_with_history("No item bound to slot " + slot_index + ".", true);
return;
}
if (!equipment_available(equip_type)) {
screen_reader_speak("Item not available.", true);
speak_with_history("Item not available.", true);
return;
}
equip_equipment_type(equip_type);
update_max_health_from_equipment();
screen_reader_speak(get_equipment_name(equip_type) + " equipped.", true);
speak_with_history(get_equipment_name(equip_type) + " equipped.", true);
}
void check_quick_slot_keys() {

View File

@@ -10,7 +10,7 @@ void check_inventory_keys(int x) {
run_inventory_root_menu();
} else {
if (in_base && world_storages.length() == 0) {
screen_reader_speak("No storage built.", true);
speak_with_history("No storage built.", true);
}
run_inventory_menu(false);
}
@@ -37,7 +37,7 @@ void menu_background_tick() {
if (fire_on_tile != null && !jumping && fire_damage_timer.elapsed > 1000) {
player_health--;
fire_damage_timer.restart();
screen_reader_speak("Burning! " + player_health + " health remaining.", true);
speak_with_history("Burning! " + player_health + " health remaining.", true);
}
// Healing in base area
@@ -48,13 +48,13 @@ void menu_background_tick() {
if (healing_timer.elapsed > heal_interval) {
player_health++;
healing_timer.restart();
screen_reader_speak(player_health + " health.", true);
speak_with_history(player_health + " health.", true);
}
}
// Death check
if (player_health <= 0) {
screen_reader_speak("You have died.", true);
speak_with_history("You have died.", true);
wait(2000);
exit();
}
@@ -106,11 +106,11 @@ string get_base_fire_status() {
void run_base_info_menu() {
if (x > BASE_END) {
screen_reader_speak("You are not in the base.", true);
speak_with_history("You are not in the base.", true);
return;
}
screen_reader_speak("Base info.", true);
speak_with_history("Base info.", true);
int selection = 0;
string[] options;
@@ -143,20 +143,20 @@ void run_base_info_menu() {
wait(5);
menu_background_tick();
if (key_pressed(KEY_ESCAPE)) {
screen_reader_speak("Closed.", true);
speak_with_history("Closed.", true);
break;
}
if (key_pressed(KEY_DOWN)) {
selection++;
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
selection--;
if (selection < 0) selection = options.length() - 1;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
}
}
@@ -200,7 +200,7 @@ void show_character_info() {
}
info += "Favor " + format_favor(favor) + ". ";
info += "Speed " + get_speed_status() + ".";
screen_reader_speak(info, true);
speak_with_history(info, true);
}
int prompt_transfer_amount(const string prompt, int max_amount) {
@@ -236,12 +236,12 @@ void move_small_game_to_personal(int amount) {
void deposit_item(int item_type) {
int available = get_personal_count(item_type);
if (available <= 0) {
screen_reader_speak("Nothing to deposit.", true);
speak_with_history("Nothing to deposit.", true);
return;
}
int capacity = BASE_STORAGE_MAX - get_storage_count(item_type);
if (capacity <= 0) {
screen_reader_speak("Storage for that item is full.", true);
speak_with_history("Storage for that item is full.", true);
return;
}
int max_transfer = (available < capacity) ? available : capacity;
@@ -277,27 +277,23 @@ void deposit_item(int item_type) {
else if (item_type == ITEM_SKIN_POUCHES) { inv_skin_pouches -= amount; storage_skin_pouches += amount; }
cleanup_equipment_after_inventory_change();
screen_reader_speak("Deposited " + amount + " " + get_item_label(item_type) + ".", true);
speak_with_history("Deposited " + amount + " " + get_item_label(item_type) + ".", true);
}
void deposit_item_max(int item_type) {
int available = get_personal_count(item_type);
if (available <= 0) {
screen_reader_speak("Nothing to deposit.", true);
speak_with_history("Nothing to deposit.", true);
return;
}
int storage_total = get_storage_total_items();
if (storage_total >= BASE_STORAGE_MAX) {
screen_reader_speak("Storage is full.", true);
int capacity = BASE_STORAGE_MAX - get_storage_count(item_type);
if (capacity <= 0) {
speak_with_history("Storage for that item is full.", true);
return;
}
int capacity = BASE_STORAGE_MAX - storage_total;
int item_storage = get_storage_count(item_type);
int item_capacity = BASE_STORAGE_MAX - item_storage;
int amount = (available < capacity) ? available : capacity;
if (amount > item_capacity) amount = item_capacity;
if (item_type == ITEM_STICKS) { inv_sticks -= amount; storage_sticks += amount; }
else if (item_type == ITEM_VINES) { inv_vines -= amount; storage_vines += amount; }
@@ -328,18 +324,18 @@ void deposit_item_max(int item_type) {
else if (item_type == ITEM_SKIN_POUCHES) { inv_skin_pouches -= amount; storage_skin_pouches += amount; }
cleanup_equipment_after_inventory_change();
screen_reader_speak("Deposited " + amount + " " + get_item_label(item_type) + ".", true);
speak_with_history("Deposited " + amount + " " + get_item_label(item_type) + ".", true);
}
void withdraw_item(int item_type) {
int available = get_storage_count(item_type);
if (available <= 0) {
screen_reader_speak("Nothing to withdraw.", true);
speak_with_history("Nothing to withdraw.", true);
return;
}
int capacity = get_personal_stack_limit() - get_personal_count(item_type);
if (capacity <= 0) {
screen_reader_speak("You can't carry any more " + get_item_label(item_type) + ".", true);
speak_with_history("You can't carry any more " + get_item_label(item_type) + ".", true);
return;
}
int max_transfer = (available < capacity) ? available : capacity;
@@ -374,13 +370,13 @@ void withdraw_item(int item_type) {
else if (item_type == ITEM_MOCCASINS) { storage_moccasins -= amount; inv_moccasins += amount; }
else if (item_type == ITEM_SKIN_POUCHES) { storage_skin_pouches -= amount; inv_skin_pouches += amount; }
screen_reader_speak("Withdrew " + amount + " " + get_item_label(item_type) + ".", true);
speak_with_history("Withdrew " + amount + " " + get_item_label(item_type) + ".", true);
}
void withdraw_item_max(int item_type) {
int available = get_storage_count(item_type);
if (available <= 0) {
screen_reader_speak("Nothing to withdraw.", true);
speak_with_history("Nothing to withdraw.", true);
return;
}
@@ -389,7 +385,7 @@ void withdraw_item_max(int item_type) {
int space = personal_limit - current_personal;
if (space <= 0) {
screen_reader_speak("Can't carry any more.", true);
speak_with_history("Can't carry any more.", true);
return;
}
@@ -423,13 +419,13 @@ void withdraw_item_max(int item_type) {
else if (item_type == ITEM_MOCCASINS) { storage_moccasins -= amount; inv_moccasins += amount; }
else if (item_type == ITEM_SKIN_POUCHES) { storage_skin_pouches -= amount; inv_skin_pouches += amount; }
screen_reader_speak("Withdrew " + amount + " " + get_item_label(item_type) + ".", true);
speak_with_history("Withdrew " + amount + " " + get_item_label(item_type) + ".", true);
}
void sacrifice_item(int item_type) {
int available = get_personal_count(item_type);
if (available <= 0) {
screen_reader_speak("Nothing to sacrifice.", true);
speak_with_history("Nothing to sacrifice.", true);
return;
}
@@ -469,13 +465,13 @@ void sacrifice_item(int item_type) {
cleanup_equipment_after_inventory_change();
double favor_gain = get_item_favor_value(item_type);
favor += favor_gain;
screen_reader_speak("Sacrificed 1 " + get_item_label_singular(item_type) + ". Favor +" + format_favor(favor_gain) + ". Total " + format_favor(favor) + ".", true);
speak_with_history("Sacrificed 1 " + get_item_label_singular(item_type) + ". Favor +" + format_favor(favor_gain) + ". Total " + format_favor(favor) + ".", true);
}
void sacrifice_item_max(int item_type) {
int available = get_personal_count(item_type);
if (available <= 0) {
screen_reader_speak("Nothing to sacrifice.", true);
speak_with_history("Nothing to sacrifice.", true);
return;
}
@@ -516,7 +512,7 @@ void sacrifice_item_max(int item_type) {
double total_favor = favor_per_item * available;
favor += total_favor;
screen_reader_speak("Sacrificed " + available + " " + get_item_label(item_type) + ". Favor +" + format_favor(total_favor) + ". Total " + format_favor(favor) + ".", true);
speak_with_history("Sacrificed " + available + " " + get_item_label(item_type) + ". Favor +" + format_favor(total_favor) + ". Total " + format_favor(favor) + ".", true);
}
void build_personal_inventory_options(string[]@ options, int[]@ item_types) {
@@ -599,11 +595,11 @@ void show_inventory() {
info += inv_incense + " incense. ";
info += "Tools: " + inv_spears + " spears, " + inv_slings + " slings, " + inv_axes + " axes, " + inv_snares + " snares, " + inv_knives + " knives, " + inv_fishing_poles + " fishing poles, " + inv_ropes + " ropes, " + inv_reed_baskets + " reed baskets, " + inv_clay_pots + " clay pots. ";
info += "Clothing: " + inv_skin_hats + " hats, " + inv_skin_gloves + " gloves, " + inv_skin_pants + " pants, " + inv_skin_tunics + " tunics, " + inv_moccasins + " moccasins, " + inv_skin_pouches + " skin pouches.";
screen_reader_speak(info, true);
speak_with_history(info, true);
}
void run_inventory_root_menu() {
screen_reader_speak("Inventory menu.", true);
speak_with_history("Inventory menu.", true);
int selection = 0;
string[] options = {"Personal inventory", "Base storage"};
@@ -612,20 +608,20 @@ void run_inventory_root_menu() {
wait(5);
menu_background_tick();
if (key_pressed(KEY_ESCAPE)) {
screen_reader_speak("Closed.", true);
speak_with_history("Closed.", true);
break;
}
if (key_pressed(KEY_DOWN)) {
selection++;
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
selection--;
if (selection < 0) selection = options.length() - 1;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
@@ -637,7 +633,7 @@ void run_inventory_root_menu() {
}
void run_inventory_menu(bool allow_deposit) {
screen_reader_speak("Inventory menu.", true);
speak_with_history("Inventory menu.", true);
int selection = 0;
string[] options;
@@ -648,45 +644,45 @@ void run_inventory_menu(bool allow_deposit) {
wait(5);
menu_background_tick();
if (key_pressed(KEY_ESCAPE)) {
screen_reader_speak("Closed.", true);
speak_with_history("Closed.", true);
break;
}
if (key_pressed(KEY_DOWN)) {
selection++;
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
selection--;
if (selection < 0) selection = options.length() - 1;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (allow_deposit && key_pressed(KEY_RETURN)) {
deposit_item(item_types[selection]);
build_personal_inventory_options(options, item_types);
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (allow_deposit && key_pressed(KEY_TAB)) {
deposit_item_max(item_types[selection]);
build_personal_inventory_options(options, item_types);
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
}
}
void run_storage_menu() {
if (world_storages.length() == 0) {
screen_reader_speak("No storage built.", true);
speak_with_history("No storage built.", true);
return;
}
screen_reader_speak("Base storage.", true);
speak_with_history("Base storage.", true);
int selection = 0;
string[] options;
@@ -697,34 +693,34 @@ void run_storage_menu() {
wait(5);
menu_background_tick();
if (key_pressed(KEY_ESCAPE)) {
screen_reader_speak("Closed.", true);
speak_with_history("Closed.", true);
break;
}
if (key_pressed(KEY_DOWN)) {
selection++;
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
selection--;
if (selection < 0) selection = options.length() - 1;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
withdraw_item(item_types[selection]);
build_storage_inventory_options(options, item_types);
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_TAB)) {
withdraw_item_max(item_types[selection]);
build_storage_inventory_options(options, item_types);
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
}
}
@@ -734,13 +730,13 @@ void check_altar_menu(int player_x) {
// Must be in base
if (player_x > BASE_END) {
screen_reader_speak("Must be in base to use altar.", true);
speak_with_history("Must be in base to use altar.", true);
return;
}
// Must have altar
if (world_altars.length() == 0) {
screen_reader_speak("No altar built.", true);
speak_with_history("No altar built.", true);
return;
}
@@ -748,7 +744,7 @@ void check_altar_menu(int player_x) {
}
void run_altar_menu() {
screen_reader_speak("Altar. Favor " + format_favor(favor) + ".", true);
speak_with_history("Altar. Favor " + format_favor(favor) + ".", true);
int selection = 0;
string[] options;
@@ -759,34 +755,34 @@ void run_altar_menu() {
wait(5);
menu_background_tick();
if (key_pressed(KEY_ESCAPE)) {
screen_reader_speak("Closed.", true);
speak_with_history("Closed.", true);
break;
}
if (key_pressed(KEY_DOWN)) {
selection++;
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
selection--;
if (selection < 0) selection = options.length() - 1;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
sacrifice_item(item_types[selection]);
build_personal_inventory_options(options, item_types);
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_TAB)) {
sacrifice_item_max(item_types[selection]);
build_personal_inventory_options(options, item_types);
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
}
}
@@ -795,15 +791,15 @@ void try_place_snare(int x) {
if (inv_snares > 0) {
// Prevent placing if one already exists here
if (get_snare_at(x) != null) {
screen_reader_speak("There is already a snare here.", true);
speak_with_history("There is already a snare here.", true);
return;
}
inv_snares--;
add_world_snare(x);
screen_reader_speak("Snare set.", true);
speak_with_history("Snare set.", true);
} else {
screen_reader_speak("No snares to place.", true);
speak_with_history("No snares to place.", true);
}
}
@@ -811,7 +807,7 @@ void try_feed_fire_stick(WorldFire@ fire) {
if (inv_sticks > 0 && fire != null) {
inv_sticks--;
fire.add_fuel(300000); // 5 minutes
screen_reader_speak("You dump an arm load of sticks into the fire.", true);
speak_with_history("You dump an arm load of sticks into the fire.", true);
p.play_stationary("sounds/actions/feed_fire.ogg", false);
}
}
@@ -820,7 +816,7 @@ void try_feed_fire_vine(WorldFire@ fire) {
if (inv_vines > 0 && fire != null) {
inv_vines--;
fire.add_fuel(60000); // 1 minute
screen_reader_speak("You toss a fiew vines and leaves into the fire.", true);
speak_with_history("You toss a fiew vines and leaves into the fire.", true);
p.play_stationary("sounds/actions/feed_fire.ogg", false);
}
}
@@ -829,34 +825,34 @@ void try_feed_fire_log(WorldFire@ fire) {
if (inv_logs > 0 && fire != null) {
inv_logs--;
fire.add_fuel(720000); // 12 minutes
screen_reader_speak("You heave a log into the fire.", true);
speak_with_history("You heave a log into the fire.", true);
p.play_stationary("sounds/actions/feed_fire.ogg", false);
}
}
void try_burn_incense() {
if (world_altars.length() == 0) {
screen_reader_speak("No altar built.", true);
speak_with_history("No altar built.", true);
return;
}
if (inv_clay_pots <= 0) {
screen_reader_speak("You need a clay pot to burn incense.", true);
speak_with_history("You need a clay pot to burn incense.", true);
return;
}
if (inv_incense <= 0) {
screen_reader_speak("No incense to burn.", true);
speak_with_history("No incense to burn.", true);
return;
}
inv_incense--;
incense_hours_remaining += INCENSE_HOURS_PER_STICK;
incense_burning = true;
screen_reader_speak("Incense burning. " + incense_hours_remaining + " hours remaining.", true);
speak_with_history("Incense burning. " + incense_hours_remaining + " hours remaining.", true);
}
void try_feed_fire_stick_max(WorldFire@ fire) {
if (inv_sticks <= 0 || fire == null) {
screen_reader_speak("No sticks to feed fire.", true);
speak_with_history("No sticks to feed fire.", true);
return;
}
@@ -866,12 +862,12 @@ void try_feed_fire_stick_max(WorldFire@ fire) {
fire.add_fuel(fuel_added);
p.play_stationary("sounds/actions/feed_fire.ogg", false);
screen_reader_speak("Dumped " + amount + " sticks into the fire.", true);
speak_with_history("Dumped " + amount + " sticks into the fire.", true);
}
void try_feed_fire_vine_max(WorldFire@ fire) {
if (inv_vines <= 0 || fire == null) {
screen_reader_speak("No vines to feed fire.", true);
speak_with_history("No vines to feed fire.", true);
return;
}
@@ -881,12 +877,12 @@ void try_feed_fire_vine_max(WorldFire@ fire) {
fire.add_fuel(fuel_added);
p.play_stationary("sounds/actions/feed_fire.ogg", false);
screen_reader_speak("Dumped " + amount + " vines into the fire.", true);
speak_with_history("Dumped " + amount + " vines into the fire.", true);
}
void try_feed_fire_log_max(WorldFire@ fire) {
if (inv_logs <= 0 || fire == null) {
screen_reader_speak("No logs to feed fire.", true);
speak_with_history("No logs to feed fire.", true);
return;
}
@@ -896,20 +892,20 @@ void try_feed_fire_log_max(WorldFire@ fire) {
fire.add_fuel(fuel_added);
p.play_stationary("sounds/actions/feed_fire.ogg", false);
screen_reader_speak("Dumped " + amount + " logs into the fire.", true);
speak_with_history("Dumped " + amount + " logs into the fire.", true);
}
void try_burn_incense_max() {
if (world_altars.length() == 0) {
screen_reader_speak("No altar built.", true);
speak_with_history("No altar built.", true);
return;
}
if (inv_clay_pots <= 0) {
screen_reader_speak("You need a clay pot to burn incense.", true);
speak_with_history("You need a clay pot to burn incense.", true);
return;
}
if (inv_incense <= 0) {
screen_reader_speak("No incense to burn.", true);
speak_with_history("No incense to burn.", true);
return;
}
@@ -921,7 +917,7 @@ void try_burn_incense_max() {
incense_hours_remaining += total_hours;
incense_burning = true;
screen_reader_speak("Burned " + amount + " incense. +" + total_hours + " hours.", true);
speak_with_history("Burned " + amount + " incense. +" + total_hours + " hours.", true);
}
void check_equipment_menu() {
@@ -930,7 +926,7 @@ void check_equipment_menu() {
if (inv_spears == 0 && inv_axes == 0 && inv_slings == 0 &&
inv_skin_hats == 0 && inv_skin_gloves == 0 && inv_skin_pants == 0 &&
inv_skin_tunics == 0 && inv_moccasins == 0 && inv_skin_pouches == 0) {
screen_reader_speak("Nothing to equip.", true);
speak_with_history("Nothing to equip.", true);
} else {
run_equipment_menu();
}
@@ -938,7 +934,7 @@ void check_equipment_menu() {
}
void run_action_menu(int x) {
screen_reader_speak("Action menu.", true);
speak_with_history("Action menu.", true);
int selection = 0;
string[] options;
@@ -976,20 +972,20 @@ void run_action_menu(int x) {
wait(5);
menu_background_tick();
if (key_pressed(KEY_ESCAPE)) {
screen_reader_speak("Closed.", true);
speak_with_history("Closed.", true);
break;
}
if (key_pressed(KEY_DOWN)) {
selection++;
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
selection--;
if (selection < 0) selection = options.length() - 1;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {
@@ -1011,7 +1007,7 @@ void run_action_menu(int x) {
if (key_pressed(KEY_TAB)) {
int action = action_types[selection];
if (action == 0) {
screen_reader_speak("Can't do that.", true);
speak_with_history("Can't do that.", true);
} else if (action == 1) {
try_feed_fire_stick_max(nearby_fire);
} else if (action == 2) {
@@ -1027,7 +1023,7 @@ void run_action_menu(int x) {
}
void run_equipment_menu() {
screen_reader_speak("Equipment menu.", true);
speak_with_history("Equipment menu.", true);
int selection = 0;
string[] options;
@@ -1084,37 +1080,37 @@ void run_equipment_menu() {
wait(5);
menu_background_tick();
if (key_pressed(KEY_ESCAPE)) {
screen_reader_speak("Closed.", true);
speak_with_history("Closed.", true);
break;
}
if (key_pressed(KEY_DOWN)) {
selection++;
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
selection--;
if (selection < 0) selection = options.length() - 1;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
int slot_index = get_quick_slot_key();
if (slot_index != -1) {
int equip_type = equipment_types[selection];
quick_slots[slot_index] = equip_type;
screen_reader_speak(get_equipment_name(equip_type) + " set to slot " + slot_index + ".", true);
speak_with_history(get_equipment_name(equip_type) + " set to slot " + slot_index + ".", true);
}
if (key_pressed(KEY_RETURN)) {
int equip_type = equipment_types[selection];
if (equipment_is_equipped(equip_type)) {
unequip_equipment_type(equip_type);
screen_reader_speak(get_equipment_name(equip_type) + " unequipped.", true);
speak_with_history(get_equipment_name(equip_type) + " unequipped.", true);
} else {
equip_equipment_type(equip_type);
screen_reader_speak(get_equipment_name(equip_type) + " equipped.", true);
speak_with_history(get_equipment_name(equip_type) + " equipped.", true);
}
update_max_health_from_equipment();
break;

View File

@@ -43,7 +43,7 @@ void update_notifications() {
return; // Still playing, wait
}
// Sound finished, now speak
screen_reader_speak(notification_queue[0], true);
speak_with_history(notification_queue[0], true);
notification_queue.remove_at(0);
notification_sound_handle = -1;
@@ -61,46 +61,46 @@ void check_notification_keys() {
// [ for previous notification (older) with position
if (key_pressed(KEY_LEFTBRACKET)) {
if (notification_history.length() == 0) {
screen_reader_speak("No notifications.", true);
speak_with_history("No notifications.", true);
return;
}
current_notification_index--;
if (current_notification_index < 0) {
current_notification_index = 0;
screen_reader_speak("Oldest notification.", true);
speak_with_history("Oldest notification. " + notification_history[current_notification_index], true);
return;
}
int position = current_notification_index + 1;
screen_reader_speak(notification_history[current_notification_index] + " " + position + " of " + notification_history.length(), true);
speak_with_history(notification_history[current_notification_index] + " " + position + " of " + notification_history.length(), true);
return;
}
// ] for next notification (newer) with position
if (key_pressed(KEY_RIGHTBRACKET)) {
if (notification_history.length() == 0) {
screen_reader_speak("No notifications.", true);
speak_with_history("No notifications.", true);
return;
}
current_notification_index++;
if (current_notification_index >= notification_history.length()) {
current_notification_index = notification_history.length() - 1;
screen_reader_speak("Most recent notification.", true);
speak_with_history("Newest notification. " + notification_history[current_notification_index], true);
return;
}
int position = current_notification_index + 1;
screen_reader_speak(notification_history[current_notification_index] + " " + position + " of " + notification_history.length(), true);
speak_with_history(notification_history[current_notification_index] + " " + position + " of " + notification_history.length(), true);
return;
}
// \ for most recent notification (without position)
if (key_pressed(KEY_BACKSLASH)) {
if (notification_history.length() == 0) {
screen_reader_speak("No notifications.", true);
speak_with_history("No notifications.", true);
return;
}
current_notification_index = notification_history.length() - 1;
screen_reader_speak(notification_history[current_notification_index], true);
speak_with_history(notification_history[current_notification_index], true);
}
}

View File

@@ -62,11 +62,11 @@ void attempt_daily_quest() {
void check_quest_menu() {
if (key_pressed(KEY_Q)) {
if (x > BASE_END) {
screen_reader_speak("You are not in the base.", true);
speak_with_history("You are not in the base.", true);
return;
}
if (quest_queue.length() == 0) {
screen_reader_speak("No quests available.", true);
speak_with_history("No quests available.", true);
return;
}
run_quest_menu();
@@ -75,7 +75,7 @@ void check_quest_menu() {
void apply_quest_reward(int score) {
if (score <= 0) {
screen_reader_speak("No reward earned.", true);
speak_with_history("No reward earned.", true);
return;
}
@@ -97,11 +97,11 @@ void apply_quest_reward(int score) {
if (stones_gain > 0) message += " Stones +" + stones_added + ".";
if (logs_gain > 0) message += " Logs +" + logs_added + ".";
if (skins_gain > 0) message += " Skins +" + skins_added + ".";
screen_reader_speak(message, true);
speak_with_history(message, true);
}
void run_quest(int quest_type) {
screen_reader_speak(get_quest_description(quest_type), true);
speak_with_history(get_quest_description(quest_type), true);
wait(800);
p.pause_all();
int score = 0;
@@ -113,7 +113,7 @@ void run_quest(int quest_type) {
}
void run_quest_menu() {
screen_reader_speak("Quest menu.", true);
speak_with_history("Quest menu.", true);
int selection = 0;
string[] options;
@@ -125,20 +125,20 @@ void run_quest_menu() {
wait(5);
menu_background_tick();
if (key_pressed(KEY_ESCAPE)) {
screen_reader_speak("Closed.", true);
speak_with_history("Closed.", true);
break;
}
if (key_pressed(KEY_DOWN)) {
selection++;
if (selection >= options.length()) selection = 0;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_UP)) {
selection--;
if (selection < 0) selection = options.length() - 1;
screen_reader_speak(options[selection], true);
speak_with_history(options[selection], true);
}
if (key_pressed(KEY_RETURN)) {

View File

@@ -2,14 +2,14 @@
string[] bat_sounds = {"sounds/quests/bat1.ogg", "sounds/quests/bat2.ogg"};
int run_bat_invasion() {
screen_reader_speak("Bat Invasion. Bats will fly past from left or right. Press space to throw your spear when the bat is centered. Press enter to continue.", true);
speak_with_history("Bat Invasion. Bats will fly past from left or right. Press space to throw your spear when the bat is centered. Press enter to continue.", true);
// Wait for enter
while (!key_pressed(KEY_RETURN)) {
wait(5);
}
screen_reader_speak("Starting.", true);
speak_with_history("Starting.", true);
wait(500);
int turns = 10;
@@ -94,6 +94,6 @@ int run_bat_invasion() {
wait(400);
}
screen_reader_speak("Bat invasion complete. Score " + score + ".", true);
speak_with_history("Bat invasion complete. Score " + score + ".", true);
return score;
}

View File

@@ -20,7 +20,7 @@ int get_note_from_key() {
}
void run_practice_mode() {
screen_reader_speak("Enchanted Melody. Repeat the magical pattern using F D R E or K J I U, from lowest to highest pitch. Practice the notes now, then press enter to begin, or escape to cancel.", true);
speak_with_history("Enchanted Melody. Repeat the magical pattern using F D R E or K J I U, from lowest to highest pitch. Practice the notes now, then press enter to begin, or escape to cancel.", true);
while (true) {
wait(5);
@@ -52,7 +52,7 @@ int run_enchanted_melody() {
return 0;
}
screen_reader_speak("Starting. Repeat the pattern.", true);
speak_with_history("Starting. Repeat the pattern.", true);
wait(500);
int[] pattern;
@@ -73,7 +73,7 @@ int run_enchanted_melody() {
play_note(note);
if (note != pattern[index]) {
int score = rounds * 2;
screen_reader_speak("You matched " + rounds + " notes. Score " + score + ".", true);
speak_with_history("You matched " + rounds + " notes. Score " + score + ".", true);
return score;
}
index++;

View File

@@ -1,13 +1,13 @@
// Escape from Hel quest game
int run_escape_from_hel() {
screen_reader_speak("Escape from Hel. You are running from the Draugr, good luck. Press space to jump over open graves as you hear them approach. Press enter to continue.", true);
speak_with_history("Escape from Hel. You are running from the Draugr, good luck. Press space to jump over open graves as you hear them approach. Press enter to continue.", true);
// Wait for enter
while (!key_pressed(KEY_RETURN)) {
wait(5);
}
screen_reader_speak("Starting.", true);
speak_with_history("Starting.", true);
wait(500);
int score = 0;
@@ -96,7 +96,7 @@ int run_escape_from_hel() {
pit_handle = -1;
}
p.play_stationary("sounds/quests/fall.ogg", false);
screen_reader_speak("You fell in. Score " + score + ".", true);
speak_with_history("You fell in. Score " + score + ".", true);
return score;
}

72
src/speech_history.nvgt Normal file
View File

@@ -0,0 +1,72 @@
// Speech History System
// Tracks last 10 unique screen reader announcements for navigation with comma/period
string[] speech_history;
const int MAX_SPEECH_HISTORY = 10;
int current_speech_index = -1;
// Main speak function - wrapper around screen_reader_speak with history tracking
void speak_with_history(string message, bool interrupt) {
// Only add to history if not already present (no duplicates)
bool already_exists = false;
for (uint i = 0; i < speech_history.length(); i++) {
if (speech_history[i] == message) {
already_exists = true;
break;
}
}
// Add to history if not a duplicate
if (!already_exists) {
speech_history.insert_last(message);
// Keep only last 10 messages
if (speech_history.length() > MAX_SPEECH_HISTORY) {
speech_history.remove_at(0);
}
// Reset index to most recent
current_speech_index = speech_history.length() - 1;
}
// Call the built-in screen_reader_speak function
screen_reader_speak(message, interrupt);
}
void check_speech_history_keys() {
// , (comma) for previous speech message (older)
if (key_pressed(KEY_COMMA)) {
if (speech_history.length() == 0) {
screen_reader_speak("No speech history.", true);
return;
}
current_speech_index--;
if (current_speech_index < 0) {
current_speech_index = 0;
screen_reader_speak("Oldest message. " + speech_history[current_speech_index], true);
return;
}
int position = current_speech_index + 1;
screen_reader_speak(speech_history[current_speech_index] + " " + position + " of " + speech_history.length(), true);
return;
}
// . (period) for next speech message (newer)
if (key_pressed(KEY_PERIOD)) {
if (speech_history.length() == 0) {
screen_reader_speak("No speech history.", true);
return;
}
current_speech_index++;
if (current_speech_index >= speech_history.length()) {
current_speech_index = speech_history.length() - 1;
screen_reader_speak("Newest message. " + speech_history[current_speech_index], true);
return;
}
int position = current_speech_index + 1;
screen_reader_speak(speech_history[current_speech_index] + " " + position + " of " + speech_history.length(), true);
return;
}
}

View File

@@ -305,7 +305,7 @@ void update_blessings() {
if (blessing_speed_active && blessing_speed_timer.elapsed >= BLESSING_SPEED_DURATION) {
blessing_speed_active = false;
update_max_health_from_equipment();
screen_reader_speak("The speed blessing fades.", true);
speak_with_history("The speed blessing fades.", true);
}
}
@@ -389,7 +389,7 @@ void update_time() {
if (storage_meat > 0) {
int gained = add_barricade_health(residents_count);
if (gained > 0 && x <= BASE_END) {
screen_reader_speak("Residents repaired the barricade. +" + gained + " health.", true);
speak_with_history("Residents repaired the barricade. +" + gained + " health.", true);
}
}
}
@@ -432,7 +432,7 @@ void update_incense_burning() {
void check_time_input() {
if (key_pressed(KEY_T)) {
screen_reader_speak(get_time_string(), true);
speak_with_history(get_time_string(), true);
}
}

View File

@@ -21,6 +21,7 @@ bool rain_fading = false;
float rain_fade_from_volume = WEATHER_MIN_VOLUME;
float rain_fade_to_volume = WEATHER_MIN_VOLUME;
timer rain_fade_timer;
int rain_fade_duration = 0; // Custom duration per fade
// Thunder object state
class ThunderStrike {
@@ -302,6 +303,10 @@ void fade_rain_to_intensity(int new_intensity) {
rain_fade_from_volume = get_rain_target_volume(rain_intensity);
rain_fade_to_volume = get_rain_target_volume(new_intensity);
// Randomize fade duration: 10-20 seconds for more natural transitions
// Longer fades feel more realistic for rain intensity changes
rain_fade_duration = random(10000, 20000);
// Start rain sound if not playing
if (rain_sound_handle == -1 && new_intensity != INTENSITY_NONE) {
rain_sound_handle = p.play_stationary(RAIN_SOUND, true);
@@ -321,7 +326,7 @@ void update_rain_fade() {
return;
}
float progress = float(rain_fade_timer.elapsed) / float(WEATHER_FADE_DURATION);
float progress = float(rain_fade_timer.elapsed) / float(rain_fade_duration);
if (progress > 1.0) progress = 1.0;
float current_vol = rain_fade_from_volume + ((rain_fade_to_volume - rain_fade_from_volume) * progress);
@@ -375,24 +380,37 @@ void spawn_thunder() {
// Spawn thunder at random distance from player
int distance = random(THUNDER_SPAWN_DISTANCE_MIN, THUNDER_SPAWN_DISTANCE_MAX);
// Determine movement: 20% stationary, 80% moving
// Determine movement: 20% stationary, 80% moving (randomly toward or away from player)
int direction = 0;
if (random(1, 100) > 20) {
direction = random(0, 1) == 0 ? -1 : 1;
}
// Random speed: 50ms (fast rip) to 600ms (slow roll)
int speed = random(50, 600);
// Thunder moves in random direction - may move toward or away from player
int spawn_direction = random(0, 1) == 0 ? -1 : 1;
direction = spawn_direction; // Movement direction matches spawn side
int thunder_pos = x + (distance * spawn_direction);
int thunder_pos = x + (distance * ((direction == 0) ? (random(0, 1) == 0 ? -1 : 1) : direction));
// Random speed: 100ms (fast rip) to 1200ms (slow roll) - halved from original
int speed = random(100, 1200);
// Play sound at position with custom volume step
int handle = play_1d_with_volume_step(thunder_file, x, thunder_pos, false, THUNDER_SOUND_VOLUME_STEP);
// Play sound at position with custom volume step
int handle = play_1d_with_volume_step(thunder_file, x, thunder_pos, false, THUNDER_SOUND_VOLUME_STEP);
if (handle != -1) {
ThunderStrike@ strike = ThunderStrike(thunder_pos, direction, handle, speed);
active_thunder.insert_last(strike);
if (handle != -1) {
ThunderStrike@ strike = ThunderStrike(thunder_pos, direction, handle, speed);
active_thunder.insert_last(strike);
}
} else {
// Stationary thunder - randomly place on either side
int spawn_side = random(0, 1) == 0 ? -1 : 1;
int thunder_pos = x + (distance * spawn_side);
// Play sound at position with custom volume step
int handle = play_1d_with_volume_step(thunder_file, x, thunder_pos, false, THUNDER_SOUND_VOLUME_STEP);
if (handle != -1) {
ThunderStrike@ strike = ThunderStrike(thunder_pos, 0, handle, 0);
active_thunder.insert_last(strike);
}
}
}

View File

@@ -271,12 +271,12 @@ void clear_world_drops() {
bool try_pickup_small_game(string game_type) {
if (inv_small_game >= get_personal_stack_limit()) {
screen_reader_speak("You can't carry any more small game.", true);
speak_with_history("You can't carry any more small game.", true);
return false;
}
inv_small_game++;
inv_small_game_types.insert_last(game_type);
screen_reader_speak("Picked up " + game_type + ".", true);
speak_with_history("Picked up " + game_type + ".", true);
return true;
}
@@ -286,14 +286,14 @@ bool try_pickup_world_drop(WorldDrop@ drop) {
}
if (drop.type == "boar carcass") {
if (inv_boar_carcasses >= get_personal_stack_limit()) {
screen_reader_speak("You can't carry any more boar carcasses.", true);
speak_with_history("You can't carry any more boar carcasses.", true);
return false;
}
inv_boar_carcasses++;
screen_reader_speak("Picked up boar carcass.", true);
speak_with_history("Picked up boar carcass.", true);
return true;
}
screen_reader_speak("Picked up " + drop.type + ".", true);
speak_with_history("Picked up " + drop.type + ".", true);
return true;
}
@@ -676,9 +676,9 @@ void check_snare_collision(int player_x) {
p.play_stationary("sounds/actions/break_snare.ogg", false);
if (s.has_catch) {
screen_reader_speak("You stepped on your snare! The " + s.catch_type + " escaped.", true);
speak_with_history("You stepped on your snare! The " + s.catch_type + " escaped.", true);
} else {
screen_reader_speak("You stepped on your snare and broke it!", true);
speak_with_history("You stepped on your snare and broke it!", true);
}
remove_snare_at(player_x);
@@ -848,7 +848,7 @@ void try_attack_barricade(Zombie@ zombie) {
if (counterDamage > 0) {
zombie.health -= counterDamage;
if (zombie.health <= 0 && x <= BASE_END) {
screen_reader_speak("Residents killed an attacking zombie.", true);
speak_with_history("Residents killed an attacking zombie.", true);
}
}
}
@@ -994,6 +994,12 @@ WorldHerbGarden@ get_herb_garden_at_base() {
void clear_bandits() {
if (bandits.length() == 0) return;
for (uint i = 0; i < bandits.length(); i++) {
if (bandits[i].sound_handle != -1) {
p.destroy_sound(bandits[i].sound_handle);
bandits[i].sound_handle = -1;
}
}
bandits.resize(0);
}
@@ -1271,7 +1277,7 @@ void try_attack_barricade_bandit(Bandit@ bandit) {
if (counterDamage > 0) {
bandit.health -= counterDamage;
if (bandit.health <= 0 && x <= BASE_END) {
screen_reader_speak("Residents killed an attacking bandit.", true);
speak_with_history("Residents killed an attacking bandit.", true);
}
}
}
@@ -1394,7 +1400,6 @@ bool damage_bandit_at(int pos, int damage) {
}
play_creature_death_sound("sounds/enemies/enemy_falls.ogg", x, pos, BANDIT_SOUND_VOLUME_STEP);
bandits.remove_at(i);
} else {
}
return true;
}
@@ -1444,9 +1449,9 @@ class MountainRange {
void generate_terrain() {
int size = int(elevations.length());
// Initialize endpoints at moderate elevations
elevations[0] = random(5, 15);
elevations[size - 1] = random(5, 15);
// Initialize endpoints at low elevations (easier transition from flat ground)
elevations[0] = random(0, 5);
elevations[size - 1] = random(0, 5);
// Use midpoint displacement for natural terrain
midpoint_displace(0, size - 1, 25);
@@ -1460,11 +1465,14 @@ class MountainRange {
// Smooth to enforce max slope constraint
smooth_slopes();
// Ensure at least one steep climb (≥7 feet) reaches into 10-20 elevation range
ensure_steep_climb();
// Assign terrain types based on elevation
for (int i = 0; i < size; i++) {
if (elevations[i] > 30) {
if (elevations[i] > 20) {
terrain_types[i] = "snow";
} else if (elevations[i] > 15) {
} else if (elevations[i] > 8) {
terrain_types[i] = "stone";
} else {
terrain_types[i] = "gravel";
@@ -1531,6 +1539,82 @@ class MountainRange {
}
}
void ensure_steep_climb() {
int size = int(elevations.length());
// Check if we already have a steep climb (≥7) to/from 10-20 elevation
bool has_steep_climb = false;
for (int i = 1; i < size; i++) {
int diff = elevations[i] - elevations[i-1];
if (diff < 0) diff = -diff;
if (diff >= MOUNTAIN_STEEP_THRESHOLD) {
// Check if either elevation is in 10-20 range
if ((elevations[i] >= 10 && elevations[i] <= 20) ||
(elevations[i-1] >= 10 && elevations[i-1] <= 20)) {
has_steep_climb = true;
break;
}
}
}
// If no steep climb to 10-20 range, create one
if (!has_steep_climb && size >= 10) {
// Pick a random position in the middle 60% of the mountain
int pos = random(int(size * 0.2), int(size * 0.8));
// Set up a steep climb: create elevation 15-18 with steep approach
int target_elevation = random(15, 18);
elevations[pos] = target_elevation;
// Make the approach from left steep (if possible)
if (pos > 0) {
elevations[pos - 1] = target_elevation - MOUNTAIN_STEEP_THRESHOLD - 1;
if (elevations[pos - 1] < MOUNTAIN_MIN_ELEVATION) {
elevations[pos - 1] = MOUNTAIN_MIN_ELEVATION;
}
}
// Make the approach from right steep (if possible)
if (pos < size - 1) {
elevations[pos + 1] = target_elevation - MOUNTAIN_STEEP_THRESHOLD - 1;
if (elevations[pos + 1] < MOUNTAIN_MIN_ELEVATION) {
elevations[pos + 1] = MOUNTAIN_MIN_ELEVATION;
}
}
// Re-smooth to ensure slopes aren't too extreme elsewhere
smooth_slopes();
}
// Ensure edge transitions aren't too steep (max 20 feet from flat ground)
// First transition: tile 0 to tile 1
if (size >= 2) {
int first_diff = elevations[1] - elevations[0];
if (first_diff < 0) first_diff = -first_diff;
if (first_diff > 20) {
if (elevations[1] > elevations[0]) {
elevations[1] = elevations[0] + 20;
} else {
elevations[1] = elevations[0] - 20;
}
}
}
// Last transition: tile size-2 to tile size-1
if (size >= 2) {
int last_diff = elevations[size-1] - elevations[size-2];
if (last_diff < 0) last_diff = -last_diff;
if (last_diff > 20) {
if (elevations[size-2] > elevations[size-1]) {
elevations[size-2] = elevations[size-1] + 20;
} else {
elevations[size-2] = elevations[size-1] - 20;
}
}
}
}
int get_elevation_at(int world_x) {
if (world_x < start_position || world_x > end_position) return 0;
int index = world_x - start_position;