Implement i18n audit/localization cleanup and sync libstorm submodule
This commit is contained in:
+16
-36
@@ -1,3 +1,5 @@
|
||||
#include "libstorm-nvgt/volume_controls.nvgt"
|
||||
|
||||
bool audio_asset_exists(const string& in soundFile) {
|
||||
if (file_exists(soundFile)) {
|
||||
return true;
|
||||
@@ -190,51 +192,29 @@ void play_player_damage_sound() {
|
||||
|
||||
// Safe sound handle cleanup - checks if handle is valid and sound is active before destroying
|
||||
void safe_destroy_sound(int& inout handle) {
|
||||
if (handle != -1) {
|
||||
if (p.sound_is_active(handle)) {
|
||||
p.destroy_sound(handle);
|
||||
}
|
||||
handle = -1;
|
||||
}
|
||||
safe_destroy_sound_in_pool(p, handle);
|
||||
}
|
||||
|
||||
float master_volume_db = MASTER_VOLUME_MAX_DB;
|
||||
|
||||
void apply_master_volume_from_controls(float volumeDb) {
|
||||
master_volume_db = volumeDb;
|
||||
sound_master_volume = volumeDb;
|
||||
}
|
||||
|
||||
void init_master_volume() {
|
||||
master_volume_db = MASTER_VOLUME_MAX_DB;
|
||||
sound_master_volume = master_volume_db;
|
||||
volume_controls_set_apply_callback(apply_master_volume_from_controls);
|
||||
volume_controls_configure(MASTER_VOLUME_MIN_DB, MASTER_VOLUME_MAX_DB, MASTER_VOLUME_STEP_DB, MASTER_VOLUME_MAX_DB);
|
||||
volume_controls_set_current_db(MASTER_VOLUME_MAX_DB, false);
|
||||
master_volume_db = volume_controls_get_current_db();
|
||||
}
|
||||
|
||||
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_db)
|
||||
return;
|
||||
|
||||
master_volume_db = clamped;
|
||||
sound_master_volume = master_volume_db;
|
||||
|
||||
if (announce) {
|
||||
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;
|
||||
screen_reader_speak("Volume " + volumePercent + ".", true);
|
||||
}
|
||||
volume_controls_set_current_db(volume_db, announce);
|
||||
master_volume_db = volume_controls_get_current_db();
|
||||
}
|
||||
|
||||
void handle_global_volume_keys() {
|
||||
if (key_pressed(KEY_PAGEDOWN)) {
|
||||
set_game_master_volume_db(master_volume_db - MASTER_VOLUME_STEP_DB);
|
||||
}
|
||||
if (key_pressed(KEY_PAGEUP)) {
|
||||
set_game_master_volume_db(master_volume_db + MASTER_VOLUME_STEP_DB);
|
||||
}
|
||||
volume_controls_handle_keys(KEY_PAGEDOWN, KEY_PAGEUP, true);
|
||||
master_volume_db = volume_controls_get_current_db();
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ void run_adventure_menu(int player_x) {
|
||||
adventure_ids.insert_last(ADVENTURE_BANDIT_HIDEOUT);
|
||||
}
|
||||
|
||||
i18n_translate_string_array_in_place(options);
|
||||
|
||||
if (options.length() == 0) {
|
||||
speak_with_history("No adventures found in this area.", true);
|
||||
return;
|
||||
|
||||
@@ -302,10 +302,11 @@ void run_bandit_hideout_adventure() {
|
||||
intro.insert_last("The base lies far to the east, guarded by a barricade.");
|
||||
intro.insert_last("");
|
||||
intro.insert_last("Objective:");
|
||||
intro.insert_last(" - Reach the base and destroy the barricade");
|
||||
intro.insert_last("- Reach the base and destroy the barricade");
|
||||
intro.insert_last("");
|
||||
intro.insert_last("Bandits will, of course, not take this lying down.");
|
||||
text_reader_lines(intro, "Adventure", true);
|
||||
i18n_translate_string_array_in_place(intro);
|
||||
text_reader_lines(intro, i18n_text("Adventure"), true);
|
||||
|
||||
begin_pet_adventure(@pet_find_hideout_target, @pet_damage_hideout_target, hideoutPlayerX);
|
||||
|
||||
@@ -522,7 +523,7 @@ void update_hideout_search() {
|
||||
|
||||
void perform_hideout_search() {
|
||||
if (random(1, 100) <= 10) {
|
||||
speak_with_history("Found nothing.", true);
|
||||
speak_with_history(tr("system.search.found_nothing"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -533,7 +534,7 @@ void perform_hideout_search() {
|
||||
}
|
||||
}
|
||||
|
||||
speak_with_history("Found nothing.", true);
|
||||
speak_with_history(tr("system.search.found_nothing"), true);
|
||||
}
|
||||
|
||||
int get_hideout_melee_weapon_type() {
|
||||
@@ -763,7 +764,7 @@ int add_hideout_storage_item(int itemType, int amount) {
|
||||
|
||||
if (itemType == ITEM_SMALL_GAME) {
|
||||
for (int i = 0; i < addedAmount; i++) {
|
||||
storage_small_game_types.insert_last("small game");
|
||||
storage_small_game_types.insert_last(i18n_text("small game"));
|
||||
}
|
||||
}
|
||||
if (itemType == ITEM_FISH) {
|
||||
@@ -856,6 +857,7 @@ void give_bandit_hideout_rewards() {
|
||||
}
|
||||
}
|
||||
|
||||
text_reader_lines(rewards, "Bandit's Hideout", true);
|
||||
i18n_translate_string_array_in_place(rewards);
|
||||
text_reader_lines(rewards, i18n_text("Bandit's Hideout"), true);
|
||||
attempt_pet_offer_from_adventure();
|
||||
}
|
||||
|
||||
@@ -110,14 +110,15 @@ void run_unicorn_adventure() {
|
||||
intro.insert_last("that can be destroyed with an axe.");
|
||||
intro.insert_last("");
|
||||
intro.insert_last("Strategy:");
|
||||
intro.insert_last(" - Use your axe to destroy a bridge support");
|
||||
intro.insert_last(" - Lure the Unicorn onto the bridge");
|
||||
intro.insert_last(" - Or fight the Unicorn directly (it has massive health)");
|
||||
intro.insert_last(" - Jump (UP arrow) to avoid being trampled");
|
||||
intro.insert_last(" - When the bridge collapses with the Unicorn on it, you win!");
|
||||
intro.insert_last("- Use your axe to destroy a bridge support");
|
||||
intro.insert_last("- Lure the Unicorn onto the bridge");
|
||||
intro.insert_last("- Or fight the Unicorn directly (it has massive health)");
|
||||
intro.insert_last("- Jump (UP arrow) to avoid being trampled");
|
||||
intro.insert_last("- When the bridge collapses with the Unicorn on it, you win!");
|
||||
intro.insert_last("");
|
||||
intro.insert_last("Controls: LEFT/RIGHT to move, UP to jump, CTRL to attack, ESC to flee");
|
||||
text_reader_lines(intro, "Adventure", true);
|
||||
i18n_translate_string_array_in_place(intro);
|
||||
text_reader_lines(intro, i18n_text("Adventure"), true);
|
||||
|
||||
begin_pet_adventure(@pet_find_unicorn_target, @pet_damage_unicorn_target, player_arena_x);
|
||||
|
||||
@@ -723,6 +724,7 @@ void give_unicorn_rewards() {
|
||||
append_adventure_completion_rewards(ADVENTURE_UNICORN, rewards);
|
||||
|
||||
// Display rewards in text reader
|
||||
text_reader_lines(rewards, "Unicorn Victory", true);
|
||||
i18n_translate_string_array_in_place(rewards);
|
||||
text_reader_lines(rewards, i18n_text("Unicorn Victory"), true);
|
||||
attempt_pet_offer_from_adventure();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
// Crafting barricade reinforcements
|
||||
string get_barricade_option_text(const string& in key, int cost, int health) {
|
||||
dictionary args;
|
||||
args.set("cost", cost);
|
||||
args.set("health", health);
|
||||
return trf(key, args);
|
||||
}
|
||||
|
||||
void run_barricade_menu() {
|
||||
if (barricade_health >= BARRICADE_MAX_HEALTH) {
|
||||
speak_with_history("Barricade is already at full health.", true);
|
||||
@@ -10,23 +17,24 @@ 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(get_barricade_option_text("system.crafting.barricade.option.reinforce_sticks",
|
||||
BARRICADE_STICK_COST, BARRICADE_STICK_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(get_barricade_option_text("system.crafting.barricade.option.reinforce_vines",
|
||||
BARRICADE_VINE_COST, BARRICADE_VINE_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(
|
||||
get_barricade_option_text("system.crafting.barricade.option.reinforce_log", BARRICADE_LOG_COST,
|
||||
BARRICADE_LOG_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(get_barricade_option_text("system.crafting.barricade.option.reinforce_stones",
|
||||
BARRICADE_STONE_COST, BARRICADE_STONE_HEALTH));
|
||||
action_types.insert_last(3);
|
||||
}
|
||||
|
||||
@@ -34,7 +42,7 @@ void run_barricade_menu() {
|
||||
speak_with_history("No materials to reinforce the barricade.", true);
|
||||
return;
|
||||
}
|
||||
speak_with_history("Barricade. " + options[selection], true);
|
||||
speak_menu_prompt("system.crafting.barricade.prompt", options[selection]);
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
@@ -171,7 +179,7 @@ void reinforce_barricade_max_with_sticks() {
|
||||
}
|
||||
|
||||
if (get_personal_count(ITEM_STICKS) < BARRICADE_STICK_COST) {
|
||||
speak_with_history("Missing: " + BARRICADE_STICK_COST + " sticks", true);
|
||||
speak_crafting_missing(BARRICADE_STICK_COST + " sticks");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -200,7 +208,7 @@ void reinforce_barricade_max_with_vines() {
|
||||
}
|
||||
|
||||
if (get_personal_count(ITEM_VINES) < BARRICADE_VINE_COST) {
|
||||
speak_with_history("Missing: " + BARRICADE_VINE_COST + " vines", true);
|
||||
speak_crafting_missing(BARRICADE_VINE_COST + " vines");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -229,7 +237,7 @@ void reinforce_barricade_max_with_log() {
|
||||
}
|
||||
|
||||
if (get_personal_count(ITEM_LOGS) < BARRICADE_LOG_COST) {
|
||||
speak_with_history("Missing: " + BARRICADE_LOG_COST + " log", true);
|
||||
speak_crafting_missing(BARRICADE_LOG_COST + " log");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -257,7 +265,7 @@ void reinforce_barricade_max_with_stones() {
|
||||
}
|
||||
|
||||
if (get_personal_count(ITEM_STONES) < BARRICADE_STONE_COST) {
|
||||
speak_with_history("Missing: " + BARRICADE_STONE_COST + " stones", true);
|
||||
speak_crafting_missing(BARRICADE_STONE_COST + " stones");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,44 +55,44 @@ void run_buildings_menu() {
|
||||
// Firepit and Fire are always available outside base,
|
||||
// but only one of each can exist in base.
|
||||
if (x > BASE_END || !base_has_firepit) {
|
||||
options.insert_last("Firepit (9 Stones)");
|
||||
options.insert_last(tr("system.crafting.buildings.option.firepit"));
|
||||
building_types.insert_last(0);
|
||||
}
|
||||
if (x > BASE_END || !base_has_fire) {
|
||||
options.insert_last("Fire (2 Sticks, 1 Log) [Requires Firepit]");
|
||||
options.insert_last(tr("system.crafting.buildings.option.fire"));
|
||||
building_types.insert_last(1);
|
||||
}
|
||||
|
||||
// Only show herb garden if not already built in base
|
||||
if (get_herb_garden_at_base() == null) {
|
||||
options.insert_last("Herb Garden (9 Stones, 3 Vines, 2 Logs) [Base Only]");
|
||||
options.insert_last(tr("system.crafting.buildings.option.herb_garden"));
|
||||
building_types.insert_last(2);
|
||||
}
|
||||
|
||||
// Storage upgrades
|
||||
if (storage_level < STORAGE_LEVEL_UPGRADE_1) {
|
||||
options.insert_last("Upgrade Storage (6 Logs, 9 Stones, 8 Vines) [Base Only, 50 each]");
|
||||
options.insert_last(tr("system.crafting.buildings.option.storage_upgrade_1"));
|
||||
building_types.insert_last(3);
|
||||
} else if (storage_level == STORAGE_LEVEL_UPGRADE_1) {
|
||||
options.insert_last("Upgrade Storage (12 Logs, 18 Stones, 16 Vines) [Base Only, 100 each]");
|
||||
options.insert_last(tr("system.crafting.buildings.option.storage_upgrade_2"));
|
||||
building_types.insert_last(3);
|
||||
}
|
||||
|
||||
// Only show pasture if not built and storage is upgraded
|
||||
if (world_pastures.length() == 0 && storage_level >= STORAGE_LEVEL_UPGRADE_1) {
|
||||
options.insert_last("Pasture (8 Logs, 18 Ropes) [Base Only, Requires Storage Upgrade]");
|
||||
options.insert_last(tr("system.crafting.buildings.option.pasture"));
|
||||
building_types.insert_last(4);
|
||||
}
|
||||
|
||||
// Only show stable if not built and storage is upgraded
|
||||
if (world_stables.length() == 0 && storage_level >= STORAGE_LEVEL_UPGRADE_1) {
|
||||
options.insert_last("Stable (10 Logs, 15 Stones, 10 Vines) [Base Only, Requires Storage Upgrade]");
|
||||
options.insert_last(tr("system.crafting.buildings.option.stable"));
|
||||
building_types.insert_last(5);
|
||||
}
|
||||
|
||||
// Only show altar if not built
|
||||
if (world_altars.length() == 0) {
|
||||
options.insert_last("Altar (9 Stones, 3 Sticks) [Base Only]");
|
||||
options.insert_last(tr("system.crafting.buildings.option.altar"));
|
||||
building_types.insert_last(6);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ void run_buildings_menu() {
|
||||
speak_with_history("No buildings available.", true);
|
||||
return;
|
||||
}
|
||||
speak_with_history("Buildings. " + options[selection], true);
|
||||
speak_menu_prompt("system.crafting.buildings.prompt", options[selection]);
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
@@ -177,7 +177,7 @@ void craft_firepit() {
|
||||
add_world_firepit(x);
|
||||
speak_with_history("Firepit built here.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ void craft_campfire() {
|
||||
add_world_fire(firepit.position);
|
||||
speak_with_history("Fire built at firepit.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ void craft_herb_garden() {
|
||||
add_world_herb_garden(x);
|
||||
speak_with_history("Herb garden built. The base now heals faster.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ void craft_storage() {
|
||||
storage_level = targetLevel;
|
||||
speak_with_history("Storage upgraded. Capacity is now " + newCapacity + " per item.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ void craft_pasture() {
|
||||
add_world_pasture(x);
|
||||
speak_with_history("Pasture built.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ void craft_stable() {
|
||||
add_world_stable(x);
|
||||
speak_with_history("Stable built.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,6 +381,6 @@ void craft_altar() {
|
||||
add_world_altar(x);
|
||||
speak_with_history("Altar built.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,14 +44,14 @@ 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)"};
|
||||
speak_with_history("Clothing. " + options[selection], true);
|
||||
string[] options = {tr("system.crafting.clothing.option.skin_hat"),
|
||||
tr("system.crafting.clothing.option.skin_gloves"),
|
||||
tr("system.crafting.clothing.option.skin_pants"),
|
||||
tr("system.crafting.clothing.option.skin_tunic"),
|
||||
tr("system.crafting.clothing.option.moccasins"),
|
||||
tr("system.crafting.clothing.option.skin_pouch"),
|
||||
tr("system.crafting.clothing.option.backpack")};
|
||||
speak_menu_prompt("system.crafting.clothing.prompt", options[selection]);
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
@@ -128,7 +128,7 @@ void craft_skin_hat() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SKIN_HATS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skin hats.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKIN_HATS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(2);
|
||||
@@ -137,13 +137,13 @@ void craft_skin_hat() {
|
||||
add_personal_count(ITEM_SKIN_HATS, 1);
|
||||
speak_with_history("Crafted a Skin Hat.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_skin_hat_max() {
|
||||
if (get_personal_count(ITEM_SKIN_HATS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skin hats.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKIN_HATS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ void craft_skin_hat_max() {
|
||||
missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ void craft_skin_gloves() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SKIN_GLOVES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skin gloves.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKIN_GLOVES);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(2);
|
||||
@@ -194,13 +194,13 @@ void craft_skin_gloves() {
|
||||
add_personal_count(ITEM_SKIN_GLOVES, 1);
|
||||
speak_with_history("Crafted Skin Gloves.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_skin_gloves_max() {
|
||||
if (get_personal_count(ITEM_SKIN_GLOVES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skin gloves.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKIN_GLOVES);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ void craft_skin_gloves_max() {
|
||||
missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ void craft_skin_pants() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SKIN_PANTS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skin pants.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKIN_PANTS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(9);
|
||||
@@ -251,13 +251,13 @@ void craft_skin_pants() {
|
||||
add_personal_count(ITEM_SKIN_PANTS, 1);
|
||||
speak_with_history("Crafted Skin Pants.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_skin_pants_max() {
|
||||
if (get_personal_count(ITEM_SKIN_PANTS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skin pants.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKIN_PANTS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ void craft_skin_pants_max() {
|
||||
missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 3)
|
||||
missing += "3 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@ void craft_skin_tunic() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SKIN_TUNICS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skin tunics.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKIN_TUNICS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(6);
|
||||
@@ -307,13 +307,13 @@ void craft_skin_tunic() {
|
||||
add_personal_count(ITEM_SKIN_TUNICS, 1);
|
||||
speak_with_history("Crafted a Skin Tunic.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_skin_tunic_max() {
|
||||
if (get_personal_count(ITEM_SKIN_TUNICS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skin tunics.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKIN_TUNICS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ void craft_skin_tunic_max() {
|
||||
missing += "4 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ void craft_moccasins() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_MOCCASINS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more moccasins.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_MOCCASINS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -363,13 +363,13 @@ void craft_moccasins() {
|
||||
add_personal_count(ITEM_MOCCASINS, 1);
|
||||
speak_with_history("Crafted moccasins.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_moccasins_max() {
|
||||
if (get_personal_count(ITEM_MOCCASINS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more moccasins.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_MOCCASINS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ void craft_moccasins_max() {
|
||||
missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ void craft_skin_pouch() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SKIN_POUCHES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skin pouches.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKIN_POUCHES);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -420,13 +420,13 @@ void craft_skin_pouch() {
|
||||
add_personal_count(ITEM_SKIN_POUCHES, 1);
|
||||
speak_with_history("Crafted a Skin Pouch.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_skin_pouch_max() {
|
||||
if (get_personal_count(ITEM_SKIN_POUCHES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skin pouches.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKIN_POUCHES);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -446,7 +446,7 @@ void craft_skin_pouch_max() {
|
||||
missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 1)
|
||||
missing += "1 vine ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -470,7 +470,7 @@ void craft_backpack() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_BACKPACKS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more backpacks.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_BACKPACKS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(20);
|
||||
@@ -480,13 +480,13 @@ void craft_backpack() {
|
||||
add_personal_count(ITEM_BACKPACKS, 1);
|
||||
speak_with_history("Crafted a Backpack.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_backpack_max() {
|
||||
if (get_personal_count(ITEM_BACKPACKS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more backpacks.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_BACKPACKS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -511,7 +511,7 @@ void craft_backpack_max() {
|
||||
missing += "5 vines ";
|
||||
if (get_total_pouch_count() < 4)
|
||||
missing += "4 skin pouches ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// Crafting materials
|
||||
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]"};
|
||||
speak_with_history("Materials. " + options[selection], true);
|
||||
string[] options = {tr("system.crafting.materials.option.butcher_game"),
|
||||
tr("system.crafting.materials.option.smoke_fish"),
|
||||
tr("system.crafting.materials.option.arrows"),
|
||||
tr("system.crafting.materials.option.bowstring"),
|
||||
tr("system.crafting.materials.option.incense")};
|
||||
speak_menu_prompt("system.crafting.materials.prompt", options[selection]);
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
@@ -94,7 +95,7 @@ void craft_arrows() {
|
||||
add_personal_count(ITEM_ARROWS, ARROWS_PER_CRAFT);
|
||||
speak_with_history("Crafted " + ARROWS_PER_CRAFT + " arrows.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ void craft_arrows_max() {
|
||||
missing += "4 feathers ";
|
||||
if (get_personal_count(ITEM_STONES) < 2)
|
||||
missing += "2 stones ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -148,7 +149,7 @@ void craft_arrows_max() {
|
||||
void craft_bowstring() {
|
||||
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);
|
||||
speak_with_history(tr("system.crafting.require.fire_within_three_bowstring"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -158,7 +159,7 @@ void craft_bowstring() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_BOWSTRINGS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more bowstrings.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_BOWSTRINGS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -166,19 +167,19 @@ void craft_bowstring() {
|
||||
add_personal_count(ITEM_BOWSTRINGS, 1);
|
||||
speak_with_history("Crafted a bowstring.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_bowstring_max() {
|
||||
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);
|
||||
speak_with_history(tr("system.crafting.require.fire_within_three_bowstring"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_personal_count(ITEM_BOWSTRINGS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more bowstrings.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_BOWSTRINGS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -190,7 +191,7 @@ void craft_bowstring_max() {
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
speak_with_history("Missing: 3 sinew", true);
|
||||
speak_crafting_missing("3 sinew");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -204,7 +205,7 @@ void craft_bowstring_max() {
|
||||
|
||||
void craft_incense() {
|
||||
if (world_altars.length() == 0) {
|
||||
speak_with_history("You need an altar to craft incense.", true);
|
||||
speak_with_history(tr("system.crafting.require.altar_incense"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -218,7 +219,7 @@ void craft_incense() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_INCENSE) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more incense.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_INCENSE);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(INCENSE_STICK_COST + INCENSE_VINE_COST + INCENSE_REED_COST);
|
||||
@@ -228,18 +229,18 @@ void craft_incense() {
|
||||
add_personal_count(ITEM_INCENSE, 1);
|
||||
speak_with_history("Crafted incense.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_incense_max() {
|
||||
if (world_altars.length() == 0) {
|
||||
speak_with_history("You need an altar to craft incense.", true);
|
||||
speak_with_history(tr("system.crafting.require.altar_incense"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_personal_count(ITEM_INCENSE) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more incense.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_INCENSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -264,7 +265,7 @@ void craft_incense_max() {
|
||||
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);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -281,7 +282,7 @@ void craft_incense_max() {
|
||||
void craft_smoke_fish() {
|
||||
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);
|
||||
speak_with_history(tr("system.crafting.require.fire_within_three_smoke_fish"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -296,7 +297,7 @@ void craft_smoke_fish() {
|
||||
int yield = get_smoked_fish_yield(weight);
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_SMOKED_FISH);
|
||||
if (space < yield) {
|
||||
speak_with_history("You can't carry any more smoked fish.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SMOKED_FISH);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(2);
|
||||
@@ -306,14 +307,14 @@ void craft_smoke_fish() {
|
||||
add_personal_count(ITEM_SMOKED_FISH, yield);
|
||||
speak_with_history("Smoked a fish into " + yield + " smoked fish.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_smoke_fish_max() {
|
||||
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);
|
||||
speak_with_history(tr("system.crafting.require.fire_within_three_smoke_fish"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,13 +330,13 @@ void craft_smoke_fish_max() {
|
||||
missing += "1 fish ";
|
||||
if (get_personal_count(ITEM_STICKS) < 1)
|
||||
missing += "1 stick ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_SMOKED_FISH);
|
||||
if (space <= 0) {
|
||||
speak_with_history("You can't carry any more smoked fish.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SMOKED_FISH);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -351,7 +352,7 @@ void craft_smoke_fish_max() {
|
||||
}
|
||||
|
||||
if (fish_to_smoke <= 0) {
|
||||
speak_with_history("You can't carry any more smoked fish.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SMOKED_FISH);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -381,17 +382,17 @@ void butcher_small_game() {
|
||||
// Check for fire within 3 tiles (can hear it)
|
||||
WorldFire @fire = get_fire_within_range(x, 3);
|
||||
if (fire == null) {
|
||||
speak_with_history("You need a fire within 3 tiles to butcher.", true);
|
||||
speak_with_history(tr("system.crafting.require.fire_within_three_butcher"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_MEAT) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more meat.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_MEAT);
|
||||
return;
|
||||
}
|
||||
if (get_personal_count(ITEM_SKINS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more skins.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKINS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(1);
|
||||
@@ -429,7 +430,7 @@ void butcher_small_game() {
|
||||
// Play sound
|
||||
p.play_stationary("sounds/items/miscellaneous.ogg", false);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,20 +439,20 @@ void butcher_small_game_max() {
|
||||
|
||||
// Check for knife
|
||||
if (get_personal_count(ITEM_KNIVES) < 1) {
|
||||
speak_with_history("Missing: Stone Knife", true);
|
||||
speak_crafting_missing("Stone Knife");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for small game or boar
|
||||
if (get_personal_count(ITEM_SMALL_GAME) < 1 && get_personal_count(ITEM_BOAR_CARCASSES) < 1) {
|
||||
speak_with_history("Missing: Game", true);
|
||||
speak_crafting_missing("Game");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for fire within 3 tiles (can hear it)
|
||||
WorldFire @fire = get_fire_within_range(x, 3);
|
||||
if (fire == null) {
|
||||
speak_with_history("You need a fire within 3 tiles to butcher.", true);
|
||||
speak_with_history(tr("system.crafting.require.fire_within_three_butcher"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -460,11 +461,11 @@ void butcher_small_game_max() {
|
||||
int skins_space = get_personal_stack_limit() - get_personal_count(ITEM_SKINS);
|
||||
|
||||
if (meat_space <= 0) {
|
||||
speak_with_history("You can't carry any more meat.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_MEAT);
|
||||
return;
|
||||
}
|
||||
if (skins_space <= 0) {
|
||||
speak_with_history("You can't carry any more skins.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SKINS);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,58 +5,58 @@
|
||||
// Get the base equipment name without any rune prefix
|
||||
string get_base_equipment_name(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR)
|
||||
return "Spear";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.spear", "Spear");
|
||||
if (equip_type == EQUIP_AXE)
|
||||
return "Stone Axe";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.stone_axe", "Stone Axe");
|
||||
if (equip_type == EQUIP_SLING)
|
||||
return "Sling";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.sling", "Sling");
|
||||
if (equip_type == EQUIP_BOW)
|
||||
return "Bow";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.bow", "Bow");
|
||||
if (equip_type == EQUIP_HAT)
|
||||
return "Skin Hat";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.skin_hat", "Skin Hat");
|
||||
if (equip_type == EQUIP_GLOVES)
|
||||
return "Skin Gloves";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.skin_gloves", "Skin Gloves");
|
||||
if (equip_type == EQUIP_PANTS)
|
||||
return "Skin Pants";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.skin_pants", "Skin Pants");
|
||||
if (equip_type == EQUIP_TUNIC)
|
||||
return "Skin Tunic";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.skin_tunic", "Skin Tunic");
|
||||
if (equip_type == EQUIP_MOCCASINS)
|
||||
return "Moccasins";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.moccasins", "Moccasins");
|
||||
if (equip_type == EQUIP_POUCH)
|
||||
return "Skin Pouch";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.skin_pouch", "Skin Pouch");
|
||||
if (equip_type == EQUIP_BACKPACK)
|
||||
return "Backpack";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.backpack", "Backpack");
|
||||
if (equip_type == EQUIP_FISHING_POLE)
|
||||
return "Fishing Pole";
|
||||
return "Unknown";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.fishing_pole", "Fishing Pole");
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.unknown", "Unknown");
|
||||
}
|
||||
|
||||
string get_base_equipment_name_plural(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR)
|
||||
return "Spears";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.spears", "Spears");
|
||||
if (equip_type == EQUIP_AXE)
|
||||
return "Stone Axes";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.stone_axes", "Stone Axes");
|
||||
if (equip_type == EQUIP_SLING)
|
||||
return "Slings";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.slings", "Slings");
|
||||
if (equip_type == EQUIP_BOW)
|
||||
return "Bows";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.bows", "Bows");
|
||||
if (equip_type == EQUIP_HAT)
|
||||
return "Skin Hats";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.skin_hats", "Skin Hats");
|
||||
if (equip_type == EQUIP_GLOVES)
|
||||
return "Skin Gloves";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.skin_gloves", "Skin Gloves");
|
||||
if (equip_type == EQUIP_PANTS)
|
||||
return "Skin Pants";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.skin_pants", "Skin Pants");
|
||||
if (equip_type == EQUIP_TUNIC)
|
||||
return "Skin Tunics";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.skin_tunics", "Skin Tunics");
|
||||
if (equip_type == EQUIP_MOCCASINS)
|
||||
return "Moccasins";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.moccasins", "Moccasins");
|
||||
if (equip_type == EQUIP_POUCH)
|
||||
return "Skin Pouches";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.skin_pouches", "Skin Pouches");
|
||||
if (equip_type == EQUIP_BACKPACK)
|
||||
return "Backpacks";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.backpacks", "Backpacks");
|
||||
if (equip_type == EQUIP_FISHING_POLE)
|
||||
return "Fishing Poles";
|
||||
return "Items";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.fishing_poles", "Fishing Poles");
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name_plural.items", "Items");
|
||||
}
|
||||
|
||||
// Get inventory count for an equipment type
|
||||
@@ -213,7 +213,7 @@ void run_rune_equipment_menu(int rune_type) {
|
||||
int unruned_count = get_unruned_equipment_count(equip_type);
|
||||
if (unruned_count > 0) {
|
||||
string name = get_base_equipment_name(equip_type);
|
||||
equipment_options.insert_last(name + " (" + unruned_count + " available)");
|
||||
equipment_options.insert_last(i18n_text(name + " (" + unruned_count + " available)"));
|
||||
equipment_types.insert_last(equip_type);
|
||||
}
|
||||
}
|
||||
@@ -302,7 +302,7 @@ void engrave_rune(int equip_type, int rune_type) {
|
||||
string runed_name = "Runed " + get_base_equipment_name(equip_type) + " of " + get_rune_effect_name(rune_type);
|
||||
speak_with_history("Engraved " + runed_name + ".", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ void engrave_rune_max(int equip_type, int rune_type) {
|
||||
max_craft = favor_count;
|
||||
|
||||
if (missing != "") {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ void engrave_rune_max(int equip_type, int rune_type) {
|
||||
missing += "1 favor ";
|
||||
if (missing == "")
|
||||
missing = "resources";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
// 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)"};
|
||||
speak_with_history("Tools. " + options[selection], true);
|
||||
string[] options = {tr("system.crafting.tools.option.stone_knife"),
|
||||
tr("system.crafting.tools.option.snare"),
|
||||
tr("system.crafting.tools.option.stone_axe"),
|
||||
tr("system.crafting.tools.option.fishing_pole"),
|
||||
tr("system.crafting.tools.option.rope"),
|
||||
tr("system.crafting.tools.option.quiver"),
|
||||
tr("system.crafting.tools.option.canoe"),
|
||||
tr("system.crafting.tools.option.reed_basket"),
|
||||
tr("system.crafting.tools.option.clay_pot")};
|
||||
speak_menu_prompt("system.crafting.tools.prompt", options[selection]);
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
@@ -93,7 +93,7 @@ void craft_knife() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_KNIVES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more stone knives.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_KNIVES);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(2);
|
||||
@@ -101,13 +101,13 @@ void craft_knife() {
|
||||
add_personal_count(ITEM_KNIVES, 1);
|
||||
speak_with_history("Crafted a Stone Knife.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_knife_max() {
|
||||
if (get_personal_count(ITEM_KNIVES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more stone knives.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_KNIVES);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ void craft_knife_max() {
|
||||
max_possible = space;
|
||||
|
||||
if (max_possible <= 0) {
|
||||
speak_with_history("Missing: 2 stones", true);
|
||||
speak_crafting_missing("2 stones");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ void craft_snare() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SNARES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more snares.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SNARES);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -147,13 +147,13 @@ void craft_snare() {
|
||||
add_personal_count(ITEM_SNARES, 1);
|
||||
speak_with_history("Crafted a Snare.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_snare_max() {
|
||||
if (get_personal_count(ITEM_SNARES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more snares.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SNARES);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ void craft_snare_max() {
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ void craft_fishing_pole() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_FISHING_POLES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more fishing poles.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_FISHING_POLES);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -204,13 +204,13 @@ void craft_fishing_pole() {
|
||||
add_personal_count(ITEM_FISHING_POLES, 1);
|
||||
speak_with_history("Crafted a Fishing Pole.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_fishing_pole_max() {
|
||||
if (get_personal_count(ITEM_FISHING_POLES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more fishing poles.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_FISHING_POLES);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ void craft_fishing_pole_max() {
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ void craft_rope() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_ROPES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more rope.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_ROPES);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -258,13 +258,13 @@ void craft_rope() {
|
||||
add_personal_count(ITEM_ROPES, 1);
|
||||
speak_with_history("Crafted rope.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_rope_max() {
|
||||
if (get_personal_count(ITEM_ROPES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more rope.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_ROPES);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ void craft_rope_max() {
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
speak_with_history("Missing: 3 vines", true);
|
||||
speak_crafting_missing("3 vines");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ void craft_quiver() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_QUIVERS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more quivers.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_QUIVERS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(4);
|
||||
@@ -305,13 +305,13 @@ void craft_quiver() {
|
||||
add_personal_count(ITEM_QUIVERS, 1);
|
||||
speak_with_history("Crafted a Quiver.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_quiver_max() {
|
||||
if (get_personal_count(ITEM_QUIVERS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more quivers.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_QUIVERS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ void craft_quiver_max() {
|
||||
missing += "2 skins ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -361,7 +361,7 @@ void craft_canoe() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_CANOES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more canoes.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_CANOES);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(40);
|
||||
@@ -374,13 +374,13 @@ void craft_canoe() {
|
||||
add_personal_count(ITEM_CANOES, 1);
|
||||
speak_with_history("Crafted a Canoe.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_canoe_max() {
|
||||
if (get_personal_count(ITEM_CANOES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more canoes.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_CANOES);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ void craft_canoe_max() {
|
||||
missing += "2 rope ";
|
||||
if (get_personal_count(ITEM_REEDS) < 6)
|
||||
missing += "6 reeds ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -444,7 +444,7 @@ void craft_reed_basket() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_REED_BASKETS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more reed baskets.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_REED_BASKETS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -452,13 +452,13 @@ void craft_reed_basket() {
|
||||
add_personal_count(ITEM_REED_BASKETS, 1);
|
||||
speak_with_history("Crafted a reed basket.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_reed_basket_max() {
|
||||
if (get_personal_count(ITEM_REED_BASKETS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more reed baskets.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_REED_BASKETS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ void craft_reed_basket_max() {
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
speak_with_history("Missing: 3 reeds", true);
|
||||
speak_crafting_missing("3 reeds");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -489,13 +489,13 @@ void craft_clay_pot() {
|
||||
// Check for fire within 3 tiles (can hear it)
|
||||
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);
|
||||
speak_with_history(tr("system.crafting.require.fire_within_three_clay_pot"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_CLAY_POTS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more clay pots.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_CLAY_POTS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -503,7 +503,7 @@ void craft_clay_pot() {
|
||||
add_personal_count(ITEM_CLAY_POTS, 1);
|
||||
speak_with_history("Crafted a clay pot.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,12 +511,12 @@ void craft_clay_pot_max() {
|
||||
// Check for fire within 3 tiles (can hear it)
|
||||
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);
|
||||
speak_with_history(tr("system.crafting.require.fire_within_three_clay_pots"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_personal_count(ITEM_CLAY_POTS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more clay pots.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_CLAY_POTS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -527,7 +527,7 @@ void craft_clay_pot_max() {
|
||||
max_craft = space;
|
||||
|
||||
if (max_craft <= 0) {
|
||||
speak_with_history("Missing: 3 clay", true);
|
||||
speak_crafting_missing("3 clay");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// 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)"};
|
||||
speak_with_history("Weapons. " + options[selection], true);
|
||||
string[] options = {tr("system.crafting.weapons.option.spear"), tr("system.crafting.weapons.option.sling"),
|
||||
tr("system.crafting.weapons.option.bow")};
|
||||
speak_menu_prompt("system.crafting.weapons.prompt", options[selection]);
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
@@ -68,7 +68,7 @@ void craft_spear() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SPEARS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more spears.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SPEARS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -78,17 +78,17 @@ void craft_spear() {
|
||||
add_personal_count(ITEM_SPEARS, 1);
|
||||
speak_with_history("Crafted a Spear.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_spear_max() {
|
||||
if (get_personal_count(ITEM_KNIVES) < 1) {
|
||||
speak_with_history("Missing: Stone Knife", true);
|
||||
speak_crafting_missing("Stone Knife");
|
||||
return;
|
||||
}
|
||||
if (get_personal_count(ITEM_SPEARS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more spears.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SPEARS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ void craft_spear_max() {
|
||||
missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_STONES) < 1)
|
||||
missing += "1 stone ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ void craft_sling() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_SLINGS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more slings.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SLINGS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -145,13 +145,13 @@ void craft_sling() {
|
||||
add_personal_count(ITEM_SLINGS, 1);
|
||||
speak_with_history("Crafted a Sling.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_sling_max() {
|
||||
if (get_personal_count(ITEM_SLINGS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more slings.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SLINGS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ void craft_sling_max() {
|
||||
missing += "1 skin ";
|
||||
if (get_personal_count(ITEM_VINES) < 2)
|
||||
missing += "2 vines ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ void craft_bow() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_BOWS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more bows.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_BOWS);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(3);
|
||||
@@ -202,13 +202,13 @@ void craft_bow() {
|
||||
add_personal_count(ITEM_BOWS, 1);
|
||||
speak_with_history("Crafted a Bow.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_bow_max() {
|
||||
if (get_personal_count(ITEM_BOWS) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more bows.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_BOWS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ void craft_bow_max() {
|
||||
missing += "1 stick ";
|
||||
if (get_personal_count(ITEM_BOWSTRINGS) < 1)
|
||||
missing += "1 bowstring ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ void craft_axe() {
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_AXES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more stone axes.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_AXES);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(4);
|
||||
@@ -264,17 +264,17 @@ void craft_axe() {
|
||||
add_personal_count(ITEM_AXES, 1);
|
||||
speak_with_history("Crafted a Stone Axe.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
void craft_axe_max() {
|
||||
if (get_personal_count(ITEM_KNIVES) < 1) {
|
||||
speak_with_history("Missing: Stone Knife", true);
|
||||
speak_crafting_missing("Stone Knife");
|
||||
return;
|
||||
}
|
||||
if (get_personal_count(ITEM_AXES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more stone axes.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_AXES);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ void craft_axe_max() {
|
||||
missing += "1 vine ";
|
||||
if (get_personal_count(ITEM_STONES) < 2)
|
||||
missing += "2 stones ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
speak_crafting_missing(missing);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,123 @@
|
||||
// Crafting core menu and shared helpers
|
||||
void speak_menu_prompt(const string& in promptKey, const string& in option) {
|
||||
dictionary args;
|
||||
args.set("option", option);
|
||||
speak_with_history(trf(promptKey, args), true);
|
||||
}
|
||||
|
||||
bool crafting_is_numeric_token(const string& in token) {
|
||||
if (token == "")
|
||||
return false;
|
||||
for (uint i = 0; i < token.length(); i++) {
|
||||
string ch = token.substr(i, 1);
|
||||
if (ch < "0" || ch > "9")
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string crafting_translate_requirement_label(const string& in englishLabel) {
|
||||
string trimmed = i18n_trim_whitespace(englishLabel);
|
||||
if (trimmed == "")
|
||||
return "";
|
||||
|
||||
string lower = trimmed.lower();
|
||||
if (lower == "stone knife")
|
||||
return tr("system.crafting.requirement.stone_knife");
|
||||
if (lower == "game")
|
||||
return tr("system.crafting.requirement.game");
|
||||
if (lower == "favor")
|
||||
return tr("system.crafting.requirement.favor");
|
||||
if (lower == "resources")
|
||||
return tr("system.crafting.requirement.resources");
|
||||
|
||||
string localized = i18n_translate_fragment_value(trimmed);
|
||||
if (localized != trimmed)
|
||||
return localized;
|
||||
|
||||
string localizedLower = i18n_translate_fragment_value(lower);
|
||||
if (localizedLower != lower)
|
||||
return localizedLower;
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
void crafting_append_requirement_fragment(string &inout joined, const string& in fragment) {
|
||||
string trimmed = i18n_trim_whitespace(fragment);
|
||||
if (trimmed == "")
|
||||
return;
|
||||
if (joined != "")
|
||||
joined += ", ";
|
||||
joined += trimmed;
|
||||
}
|
||||
|
||||
string crafting_localize_missing_requirements(const string& in missingEnglish) {
|
||||
string trimmed = i18n_trim_whitespace(missingEnglish);
|
||||
if (trimmed == "")
|
||||
return "";
|
||||
|
||||
string[] tokens = trimmed.split(" ");
|
||||
string localized = "";
|
||||
uint i = 0;
|
||||
|
||||
while (i < tokens.length()) {
|
||||
if (tokens[i] == "") {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (crafting_is_numeric_token(tokens[i])) {
|
||||
string countText = tokens[i];
|
||||
i++;
|
||||
|
||||
string label = "";
|
||||
while (i < tokens.length()) {
|
||||
if (tokens[i] == "") {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (crafting_is_numeric_token(tokens[i]))
|
||||
break;
|
||||
if (label != "")
|
||||
label += " ";
|
||||
label += tokens[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
label = crafting_translate_requirement_label(label);
|
||||
crafting_append_requirement_fragment(localized, countText + " " + label);
|
||||
continue;
|
||||
}
|
||||
|
||||
string label = "";
|
||||
while (i < tokens.length()) {
|
||||
if (tokens[i] == "") {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (crafting_is_numeric_token(tokens[i]))
|
||||
break;
|
||||
if (label != "")
|
||||
label += " ";
|
||||
label += tokens[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
label = crafting_translate_requirement_label(label);
|
||||
crafting_append_requirement_fragment(localized, label);
|
||||
}
|
||||
|
||||
if (localized == "")
|
||||
localized = crafting_translate_requirement_label(trimmed);
|
||||
return localized;
|
||||
}
|
||||
|
||||
void speak_crafting_missing(const string& in missingEnglish) {
|
||||
dictionary args;
|
||||
args.set("requirements", crafting_localize_missing_requirements(missingEnglish));
|
||||
speak_with_history(trf("system.crafting.missing", args), true);
|
||||
}
|
||||
|
||||
void check_crafting_menu(int x, int base_end_tile) {
|
||||
if (x <= base_end_tile) {
|
||||
if (key_pressed(KEY_C)) {
|
||||
@@ -13,27 +132,27 @@ void run_crafting_menu() {
|
||||
int[] category_types;
|
||||
|
||||
// Build categories dynamically
|
||||
categories.insert_last("Weapons");
|
||||
categories.insert_last(tr("system.crafting.category.weapons"));
|
||||
category_types.insert_last(0);
|
||||
categories.insert_last("Tools");
|
||||
categories.insert_last(tr("system.crafting.category.tools"));
|
||||
category_types.insert_last(1);
|
||||
categories.insert_last("Materials");
|
||||
categories.insert_last(tr("system.crafting.category.materials"));
|
||||
category_types.insert_last(2);
|
||||
categories.insert_last("Clothing");
|
||||
categories.insert_last(tr("system.crafting.category.clothing"));
|
||||
category_types.insert_last(3);
|
||||
if (has_building_options()) {
|
||||
categories.insert_last("Buildings");
|
||||
categories.insert_last(tr("system.crafting.category.buildings"));
|
||||
category_types.insert_last(4);
|
||||
}
|
||||
categories.insert_last("Barricade");
|
||||
categories.insert_last(tr("system.crafting.category.barricade"));
|
||||
category_types.insert_last(5);
|
||||
|
||||
// Add Runes category if any rune is unlocked
|
||||
if (any_rune_unlocked()) {
|
||||
categories.insert_last("Runes");
|
||||
categories.insert_last(tr("system.crafting.category.runes"));
|
||||
category_types.insert_last(6);
|
||||
}
|
||||
speak_with_history("Crafting menu. " + categories[selection], true);
|
||||
speak_menu_prompt("system.crafting.menu.prompt", categories[selection]);
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
|
||||
+30
-33
@@ -218,19 +218,19 @@ void init_search_pools() {
|
||||
@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].found_messages = {"", ""};
|
||||
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].found_messages = {"", ""};
|
||||
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].found_messages = {""};
|
||||
search_pools[SEARCH_POOL_STONE_TERRAIN].terrain_tags = {"gravel", "stone", "hard_stone"};
|
||||
|
||||
// Mass nouns for auto "Found X." fallback (no article).
|
||||
@@ -596,14 +596,19 @@ void damage_tree(int target_x, int damage) {
|
||||
add_personal_count(ITEM_VINES, vines_added);
|
||||
add_personal_count(ITEM_LOGS, logs_added);
|
||||
|
||||
string drop_message = "Tree fell!";
|
||||
string drop_message = tr("system.environment.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 + ".";
|
||||
dictionary loot_args;
|
||||
loot_args.set("sticks", sticks_added);
|
||||
loot_args.set("vines", vines_added);
|
||||
loot_args.set("logs", logs_added);
|
||||
loot_args.set("sticks_label", get_item_label_for_count(ITEM_STICKS, sticks_added));
|
||||
loot_args.set("vines_label", get_item_label_for_count(ITEM_VINES, vines_added));
|
||||
loot_args.set("logs_label", get_item_label_for_count(ITEM_LOGS, logs_added));
|
||||
drop_message = trf("system.environment.tree.fell_with_loot", loot_args);
|
||||
}
|
||||
if (sticks_added < sticks_dropped || vines_added < vines_dropped || logs_added < 1) {
|
||||
drop_message += " Inventory full.";
|
||||
drop_message += " " + tr("system.environment.tree.inventory_full");
|
||||
}
|
||||
|
||||
play_item_collect_sound("stick");
|
||||
@@ -616,7 +621,7 @@ void damage_tree(int target_x, int damage) {
|
||||
string build_item_list(int[] item_types) {
|
||||
string list_text = "";
|
||||
for (uint i = 0; i < item_types.length(); i++) {
|
||||
string item_name = item_registry[item_types[i]].name;
|
||||
string item_name = get_item_label(item_types[i]);
|
||||
if (i == 0) {
|
||||
list_text = item_name;
|
||||
} else if (i == item_types.length() - 1) {
|
||||
@@ -642,17 +647,9 @@ bool is_mass_noun_item(int item_type) {
|
||||
}
|
||||
|
||||
string get_auto_found_message(int item_type) {
|
||||
string singular = item_registry[item_type].singular;
|
||||
if (is_mass_noun_item(item_type)) {
|
||||
return "Found " + singular + ".";
|
||||
}
|
||||
|
||||
string first_letter = singular.substr(0, 1);
|
||||
if (first_letter == "a" || first_letter == "e" || first_letter == "i" || first_letter == "o" ||
|
||||
first_letter == "u") {
|
||||
return "Found an " + singular + ".";
|
||||
}
|
||||
return "Found a " + singular + ".";
|
||||
dictionary args;
|
||||
args.set("item", get_item_label_singular(item_type));
|
||||
return trf("system.search.found_item", args);
|
||||
}
|
||||
|
||||
int get_search_weight(int[] weights, uint index) {
|
||||
@@ -685,7 +682,7 @@ bool try_find_weighted_resource(int[] item_types, int[] weights, string[] found_
|
||||
}
|
||||
|
||||
if (available_indices.length() == 0) {
|
||||
speak_with_history("You can't carry any more " + build_item_list(item_types) + ".", true);
|
||||
speak_cant_carry_any_more_label(build_item_list(item_types));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -758,11 +755,11 @@ void perform_search(int current_x) {
|
||||
if (s != null) {
|
||||
if (s.has_catch) {
|
||||
if (get_personal_count(ITEM_SMALL_GAME) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more small game.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SMALL_GAME);
|
||||
return;
|
||||
}
|
||||
if (get_personal_count(ITEM_SNARES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more snares.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SNARES);
|
||||
return;
|
||||
}
|
||||
add_personal_count(ITEM_SMALL_GAME, 1);
|
||||
@@ -771,7 +768,7 @@ void perform_search(int current_x) {
|
||||
speak_with_history("Collected " + s.catch_type + " and snare.", true);
|
||||
} else {
|
||||
if (get_personal_count(ITEM_SNARES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more snares.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SNARES);
|
||||
return;
|
||||
}
|
||||
add_personal_count(ITEM_SNARES, 1); // Recover snare
|
||||
@@ -785,7 +782,7 @@ void perform_search(int current_x) {
|
||||
}
|
||||
|
||||
if (random(1, 100) <= 10) {
|
||||
speak_with_history("Found nothing.", true);
|
||||
speak_with_history(tr("system.search.found_nothing"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -865,13 +862,13 @@ void perform_search(int current_x) {
|
||||
nearest.sticks--;
|
||||
add_personal_count(ITEM_STICKS, 1);
|
||||
play_item_collect_sound("stick");
|
||||
speak_with_history("Found a stick.", true);
|
||||
speak_with_history(get_auto_found_message(ITEM_STICKS), true);
|
||||
took_item = true;
|
||||
} else if (nearest.vines > 0 && get_personal_count(ITEM_VINES) < get_personal_stack_limit()) {
|
||||
nearest.vines--;
|
||||
add_personal_count(ITEM_VINES, 1);
|
||||
play_item_collect_sound("vine");
|
||||
speak_with_history("Found a vine.", true);
|
||||
speak_with_history(get_auto_found_message(ITEM_VINES), true);
|
||||
took_item = true;
|
||||
}
|
||||
} else {
|
||||
@@ -879,24 +876,24 @@ void perform_search(int current_x) {
|
||||
nearest.vines--;
|
||||
add_personal_count(ITEM_VINES, 1);
|
||||
play_item_collect_sound("vine");
|
||||
speak_with_history("Found a vine.", true);
|
||||
speak_with_history(get_auto_found_message(ITEM_VINES), true);
|
||||
took_item = true;
|
||||
} else if (nearest.sticks > 0 && get_personal_count(ITEM_STICKS) < get_personal_stack_limit()) {
|
||||
nearest.sticks--;
|
||||
add_personal_count(ITEM_STICKS, 1);
|
||||
play_item_collect_sound("stick");
|
||||
speak_with_history("Found a stick.", true);
|
||||
speak_with_history(get_auto_found_message(ITEM_STICKS), true);
|
||||
took_item = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!took_item) {
|
||||
if (nearest.sticks > 0 && nearest.vines > 0) {
|
||||
speak_with_history("You can't carry any more sticks or vines.", true);
|
||||
speak_cant_carry_any_more_label(build_item_list({ITEM_STICKS, ITEM_VINES}));
|
||||
} else if (nearest.sticks > 0) {
|
||||
speak_with_history("You can't carry any more sticks.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_STICKS);
|
||||
} else {
|
||||
speak_with_history("You can't carry any more vines.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_VINES);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -916,7 +913,7 @@ void perform_search(int current_x) {
|
||||
return;
|
||||
}
|
||||
|
||||
speak_with_history("Found nothing.", true);
|
||||
speak_with_history(tr("system.search.found_nothing"), true);
|
||||
}
|
||||
|
||||
// Climbing functions
|
||||
|
||||
+1
-1
@@ -310,7 +310,7 @@ void update_reeling() {
|
||||
|
||||
void catch_fish() {
|
||||
if (get_personal_count(ITEM_FISH) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more fish.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_FISH);
|
||||
reset_fishing_session();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ void append_adventure_completion_rewards(int adventureId, string[] @rewards) {
|
||||
|
||||
string stageName = fylgjaStageNames[stageIndex];
|
||||
string targetName = adventureStageTargets[adventureIndex];
|
||||
rewards.insert_last("You have a " + stageName + " connection with the " + targetName + ".");
|
||||
rewards.insert_last(i18n_text("You have a " + stageName + " connection with the " + targetName + "."));
|
||||
|
||||
int fylgjaIndex = get_fylgja_index_for_adventure(adventureId);
|
||||
if (fylgjaIndex == -1)
|
||||
@@ -96,9 +96,9 @@ void append_adventure_completion_rewards(int adventureId, string[] @rewards) {
|
||||
|
||||
if (completionCount >= FYLGJA_STAGE_COUNT) {
|
||||
if (completionCount == FYLGJA_STAGE_COUNT) {
|
||||
rewards.insert_last("You have unlocked the " + fylgjaNames[fylgjaIndex] + " Fylgja!");
|
||||
rewards.insert_last(i18n_text("You have unlocked the " + fylgjaNames[fylgjaIndex] + " Fylgja!"));
|
||||
} else {
|
||||
rewards.insert_last("You have already unlocked the " + fylgjaNames[fylgjaIndex] + " Fylgja.");
|
||||
rewards.insert_last(i18n_text("You have already unlocked the " + fylgjaNames[fylgjaIndex] + " Fylgja."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,6 +129,7 @@ void run_fylgja_menu() {
|
||||
fylgjaIndices.insert_last(int(i));
|
||||
}
|
||||
}
|
||||
i18n_translate_string_array_in_place(options);
|
||||
|
||||
if (options.length() == 0)
|
||||
return;
|
||||
|
||||
+770
@@ -0,0 +1,770 @@
|
||||
// Localization and translation helpers.
|
||||
// Provides key-based lookups plus runtime template matching for existing English output.
|
||||
|
||||
const string I18N_DEFAULT_LANGUAGE_CODE = "en";
|
||||
const string I18N_LANGUAGE_DIRECTORY = "lang";
|
||||
const string I18N_ENGLISH_CATALOG_PATH = "lang/en.ini";
|
||||
const string I18N_LANGUAGE_PREF_FILENAME = "draugnorak.dat";
|
||||
const string I18N_LANGUAGE_PREF_KEY = "language";
|
||||
const string I18N_PREF_COMPANY_NAME = "stormux";
|
||||
const string I18N_PREF_PRODUCT_NAME = "Draugnorak";
|
||||
const string I18N_PREF_SUBDIR = "config";
|
||||
|
||||
string activeLanguageCode = I18N_DEFAULT_LANGUAGE_CODE;
|
||||
bool i18nInitialized = false;
|
||||
bool i18nCatalogLoaded = false;
|
||||
|
||||
dictionary @i18nEnglishCatalog = dictionary();
|
||||
dictionary @i18nActiveCatalog = dictionary();
|
||||
dictionary @i18nExactEnglishToKey = dictionary();
|
||||
dictionary @i18nMissingKeyLog = dictionary();
|
||||
|
||||
string[] i18nTemplateKeys;
|
||||
string[] i18nTemplateEnglish;
|
||||
|
||||
string i18n_trim_whitespace(string text) {
|
||||
if (text.length() == 0)
|
||||
return text;
|
||||
|
||||
int start = 0;
|
||||
int end = text.length() - 1;
|
||||
while (start <= end) {
|
||||
string ch = text.substr(start, 1);
|
||||
if (ch != " " && ch != "\t" && ch != "\r" && ch != "\n")
|
||||
break;
|
||||
start++;
|
||||
}
|
||||
|
||||
while (end >= start) {
|
||||
string ch = text.substr(end, 1);
|
||||
if (ch != " " && ch != "\t" && ch != "\r" && ch != "\n")
|
||||
break;
|
||||
end--;
|
||||
}
|
||||
|
||||
if (end < start)
|
||||
return "";
|
||||
return text.substr(start, end - start + 1);
|
||||
}
|
||||
|
||||
string i18n_trim_trailing_path_separator(string path) {
|
||||
while (path.length() > 1) {
|
||||
string last = path.substr(path.length() - 1, 1);
|
||||
if (last != "/" && last != "\\")
|
||||
break;
|
||||
path = path.substr(0, path.length() - 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
string i18n_get_path_basename(const string& in path) {
|
||||
int lastSeparator = -1;
|
||||
for (uint i = 0; i < path.length(); i++) {
|
||||
string ch = path.substr(i, 1);
|
||||
if (ch == "/" || ch == "\\") {
|
||||
lastSeparator = int(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (lastSeparator < 0)
|
||||
return path;
|
||||
int start = lastSeparator + 1;
|
||||
if (start >= int(path.length()))
|
||||
return "";
|
||||
return path.substr(start);
|
||||
}
|
||||
|
||||
string i18n_get_pref_directory_path() {
|
||||
string path = join({DIRECTORY_APPDATA, I18N_PREF_COMPANY_NAME, I18N_PREF_PRODUCT_NAME, I18N_PREF_SUBDIR}, "/");
|
||||
path = i18n_trim_trailing_path_separator(path);
|
||||
if (path == "")
|
||||
path = ".";
|
||||
|
||||
if (!directory_exists(path) && !directory_create(path)) {
|
||||
return ".";
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
string i18n_get_pref_file_path() {
|
||||
string prefDirectory = i18n_get_pref_directory_path();
|
||||
if (prefDirectory == "." || prefDirectory == "") {
|
||||
return I18N_LANGUAGE_PREF_FILENAME;
|
||||
}
|
||||
return prefDirectory + "/" + I18N_LANGUAGE_PREF_FILENAME;
|
||||
}
|
||||
|
||||
bool i18n_read_file_text(const string& in filePath, string& out content) {
|
||||
content = "";
|
||||
file handle;
|
||||
if (!handle.open(filePath, "rb"))
|
||||
return false;
|
||||
content = handle.read();
|
||||
handle.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool i18n_write_file_text(const string& in filePath, const string& in content) {
|
||||
file handle;
|
||||
if (!handle.open(filePath, "wb"))
|
||||
return false;
|
||||
int written = handle.write(content);
|
||||
handle.close();
|
||||
return written >= int(content.length());
|
||||
}
|
||||
|
||||
string i18n_unescape_catalog_value(const string& in value) {
|
||||
string result = "";
|
||||
bool escaping = false;
|
||||
|
||||
for (uint i = 0; i < value.length(); i++) {
|
||||
string ch = value.substr(i, 1);
|
||||
if (!escaping) {
|
||||
if (ch == "\\") {
|
||||
escaping = true;
|
||||
continue;
|
||||
}
|
||||
result += ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == "n") {
|
||||
result += "\n";
|
||||
} else if (ch == "r") {
|
||||
result += "\r";
|
||||
} else if (ch == "t") {
|
||||
result += "\t";
|
||||
} else {
|
||||
result += ch;
|
||||
}
|
||||
escaping = false;
|
||||
}
|
||||
|
||||
if (escaping)
|
||||
result += "\\";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool i18n_parse_catalog_line(const string& in lineText, string& out key, string& out value) {
|
||||
key = "";
|
||||
value = "";
|
||||
|
||||
string trimmed = i18n_trim_whitespace(lineText);
|
||||
if (trimmed == "")
|
||||
return false;
|
||||
if (trimmed.substr(0, 1) == ";" || trimmed.substr(0, 1) == "#")
|
||||
return false;
|
||||
|
||||
int separator = trimmed.find_first("=");
|
||||
if (separator < 0)
|
||||
return false;
|
||||
|
||||
string rawKey = i18n_trim_whitespace(trimmed.substr(0, separator));
|
||||
string rawValue = "";
|
||||
if (separator + 1 < int(trimmed.length())) {
|
||||
rawValue = i18n_trim_whitespace(trimmed.substr(separator + 1));
|
||||
}
|
||||
|
||||
if (rawKey == "")
|
||||
return false;
|
||||
|
||||
key = rawKey;
|
||||
value = i18n_unescape_catalog_value(rawValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool i18n_load_catalog_file(const string& in filePath, dictionary @catalog) {
|
||||
if (@catalog is null)
|
||||
return false;
|
||||
|
||||
catalog.clear();
|
||||
string data = "";
|
||||
if (!i18n_read_file_text(filePath, data))
|
||||
return false;
|
||||
|
||||
string[] lines = data.split("\n");
|
||||
string currentSection = "";
|
||||
for (uint i = 0; i < lines.length(); i++) {
|
||||
string line = lines[i];
|
||||
if (line.length() > 0 && line.substr(line.length() - 1) == "\r") {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
|
||||
string trimmed = i18n_trim_whitespace(line);
|
||||
if (trimmed.length() >= 2 && trimmed.substr(0, 1) == "[" && trimmed.substr(trimmed.length() - 1) == "]") {
|
||||
currentSection = i18n_trim_whitespace(trimmed.substr(1, trimmed.length() - 2));
|
||||
continue;
|
||||
}
|
||||
|
||||
string key = "";
|
||||
string value = "";
|
||||
if (!i18n_parse_catalog_line(trimmed, key, value))
|
||||
continue;
|
||||
|
||||
if (currentSection != "") {
|
||||
if (currentSection == "messages") {
|
||||
// Keep message keys stable as msg.<id> so runtime template matching can resolve them directly.
|
||||
if (key.find_first(".") < 0)
|
||||
key = currentSection + "." + key;
|
||||
} else {
|
||||
string sectionPrefix = currentSection + ".";
|
||||
if (key.find_first(sectionPrefix) != 0)
|
||||
key = sectionPrefix + key;
|
||||
}
|
||||
}
|
||||
|
||||
catalog.set(key, value);
|
||||
}
|
||||
|
||||
return catalog.get_size() > 0;
|
||||
}
|
||||
|
||||
bool i18n_catalog_get_string(dictionary @catalog, const string& in key, string& out value) {
|
||||
value = "";
|
||||
if (@catalog is null)
|
||||
return false;
|
||||
if (catalog.get(key, value))
|
||||
return true;
|
||||
|
||||
int valueInt = 0;
|
||||
if (catalog.get(key, valueInt)) {
|
||||
value = "" + valueInt;
|
||||
return true;
|
||||
}
|
||||
|
||||
double valueDouble = 0.0;
|
||||
if (catalog.get(key, valueDouble)) {
|
||||
value = "" + valueDouble;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool valueBool = false;
|
||||
if (catalog.get(key, valueBool)) {
|
||||
value = valueBool ? "true" : "false";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool i18n_has_placeholders(const string& in templateText) {
|
||||
int open = templateText.find_first("{");
|
||||
if (open < 0)
|
||||
return false;
|
||||
int close = templateText.find_first("}", open + 1);
|
||||
return close > open;
|
||||
}
|
||||
|
||||
int i18n_template_literal_length(const string& in templateText) {
|
||||
int literalCount = 0;
|
||||
bool inPlaceholder = false;
|
||||
|
||||
for (uint i = 0; i < templateText.length(); i++) {
|
||||
string ch = templateText.substr(i, 1);
|
||||
if (!inPlaceholder && ch == "{") {
|
||||
inPlaceholder = true;
|
||||
continue;
|
||||
}
|
||||
if (inPlaceholder && ch == "}") {
|
||||
inPlaceholder = false;
|
||||
continue;
|
||||
}
|
||||
if (!inPlaceholder) {
|
||||
literalCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return literalCount;
|
||||
}
|
||||
|
||||
string i18n_lookup_key_with_fallback(const string& in key, const string& in defaultValue) {
|
||||
string localized = "";
|
||||
if (@i18nActiveCatalog !is null && i18n_catalog_get_string(i18nActiveCatalog, key, localized) && localized != "") {
|
||||
return localized;
|
||||
}
|
||||
|
||||
if (@i18nEnglishCatalog !is null && i18n_catalog_get_string(i18nEnglishCatalog, key, localized) && localized != "") {
|
||||
return localized;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
void i18n_rebuild_indexes() {
|
||||
i18nExactEnglishToKey.clear();
|
||||
i18nTemplateKeys.resize(0);
|
||||
i18nTemplateEnglish.resize(0);
|
||||
|
||||
if (@i18nEnglishCatalog is null)
|
||||
return;
|
||||
|
||||
string[] @keys = i18nEnglishCatalog.get_keys();
|
||||
if (@keys is null)
|
||||
return;
|
||||
|
||||
for (uint i = 0; i < keys.length(); i++) {
|
||||
string key = keys[i];
|
||||
if (key.find_first("meta.") == 0)
|
||||
continue;
|
||||
|
||||
string english = "";
|
||||
if (!i18n_catalog_get_string(i18nEnglishCatalog, key, english))
|
||||
continue;
|
||||
if (english == "")
|
||||
continue;
|
||||
|
||||
if (i18n_has_placeholders(english)) {
|
||||
if (i18n_template_literal_length(english) == 0)
|
||||
continue;
|
||||
i18nTemplateKeys.insert_last(key);
|
||||
i18nTemplateEnglish.insert_last(english);
|
||||
} else if (!i18nExactEnglishToKey.exists(english)) {
|
||||
i18nExactEnglishToKey.set(english, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string tr(const string& in key) {
|
||||
if (key == "")
|
||||
return "";
|
||||
|
||||
string value = "";
|
||||
if (@i18nActiveCatalog !is null && i18n_catalog_get_string(i18nActiveCatalog, key, value) && value != "")
|
||||
return value;
|
||||
if (@i18nEnglishCatalog !is null && i18n_catalog_get_string(i18nEnglishCatalog, key, value) && value != "")
|
||||
return value;
|
||||
|
||||
if (!i18nMissingKeyLog.exists(key)) {
|
||||
i18nMissingKeyLog.set(key, true);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
string i18n_format_template(const string& in templateText, dictionary @args) {
|
||||
string result = "";
|
||||
uint cursor = 0;
|
||||
|
||||
while (cursor < templateText.length()) {
|
||||
int open = templateText.find_first("{", cursor);
|
||||
if (open < 0) {
|
||||
result += templateText.substr(cursor);
|
||||
break;
|
||||
}
|
||||
|
||||
result += templateText.substr(cursor, open - cursor);
|
||||
int close = templateText.find_first("}", open + 1);
|
||||
if (close < 0) {
|
||||
result += templateText.substr(open);
|
||||
break;
|
||||
}
|
||||
|
||||
string placeholder = templateText.substr(open + 1, close - open - 1);
|
||||
string replacement = "";
|
||||
if (!i18n_catalog_get_string(args, placeholder, replacement)) {
|
||||
replacement = "{" + placeholder + "}";
|
||||
}
|
||||
result += replacement;
|
||||
cursor = close + 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string trf(const string& in key, dictionary @args) {
|
||||
string templateText = tr(key);
|
||||
return i18n_format_template(templateText, args);
|
||||
}
|
||||
|
||||
string trn(const string& in baseKey, int count, dictionary @args = null) {
|
||||
string key = baseKey + ((count == 1) ? ".one" : ".other");
|
||||
|
||||
dictionary localArgs;
|
||||
dictionary @argsHandle = @args;
|
||||
if (@argsHandle is null) {
|
||||
@argsHandle = @localArgs;
|
||||
}
|
||||
argsHandle.set("count", count);
|
||||
|
||||
return trf(key, argsHandle);
|
||||
}
|
||||
|
||||
bool i18n_match_template(const string& in templateText, const string& in inputText, dictionary @captures) {
|
||||
if (@captures is null)
|
||||
return false;
|
||||
captures.clear();
|
||||
|
||||
uint templateCursor = 0;
|
||||
uint inputCursor = 0;
|
||||
|
||||
while (templateCursor < templateText.length()) {
|
||||
int open = templateText.find_first("{", templateCursor);
|
||||
if (open < 0) {
|
||||
string tail = templateText.substr(templateCursor);
|
||||
uint remaining = inputText.length() - inputCursor;
|
||||
if (tail.length() != remaining)
|
||||
return false;
|
||||
if (tail.length() > 0 && inputText.substr(inputCursor, tail.length()) != tail)
|
||||
return false;
|
||||
inputCursor = inputText.length();
|
||||
templateCursor = templateText.length();
|
||||
break;
|
||||
}
|
||||
|
||||
string literalBefore = templateText.substr(templateCursor, open - templateCursor);
|
||||
if (literalBefore.length() > 0) {
|
||||
if (inputCursor + literalBefore.length() > inputText.length())
|
||||
return false;
|
||||
if (inputText.substr(inputCursor, literalBefore.length()) != literalBefore)
|
||||
return false;
|
||||
inputCursor += literalBefore.length();
|
||||
}
|
||||
|
||||
int close = templateText.find_first("}", open + 1);
|
||||
if (close < 0)
|
||||
return false;
|
||||
|
||||
string placeholder = templateText.substr(open + 1, close - open - 1);
|
||||
if (placeholder == "")
|
||||
return false;
|
||||
|
||||
int nextOpen = templateText.find_first("{", close + 1);
|
||||
string nextLiteral = "";
|
||||
if (nextOpen >= 0) {
|
||||
nextLiteral = templateText.substr(close + 1, nextOpen - close - 1);
|
||||
} else {
|
||||
nextLiteral = templateText.substr(close + 1);
|
||||
}
|
||||
|
||||
string captured = "";
|
||||
if (nextLiteral == "") {
|
||||
if (nextOpen >= 0)
|
||||
return false;
|
||||
if (inputCursor <= inputText.length()) {
|
||||
captured = inputText.substr(inputCursor);
|
||||
}
|
||||
inputCursor = inputText.length();
|
||||
} else {
|
||||
int found = inputText.find_first(nextLiteral, inputCursor);
|
||||
if (found < 0)
|
||||
return false;
|
||||
captured = inputText.substr(inputCursor, found - inputCursor);
|
||||
inputCursor = found;
|
||||
}
|
||||
|
||||
captures.set(placeholder, captured);
|
||||
templateCursor = close + 1;
|
||||
}
|
||||
|
||||
return inputCursor == inputText.length();
|
||||
}
|
||||
|
||||
string i18n_translate_fragment_value(const string& in value) {
|
||||
if (value == "" || activeLanguageCode == I18N_DEFAULT_LANGUAGE_CODE)
|
||||
return value;
|
||||
|
||||
string key = "";
|
||||
if (!i18n_catalog_get_string(i18nExactEnglishToKey, value, key))
|
||||
return value;
|
||||
|
||||
return i18n_lookup_key_with_fallback(key, value);
|
||||
}
|
||||
|
||||
string i18n_translate_speech_message(const string& in message) {
|
||||
if (message == "")
|
||||
return message;
|
||||
if (!i18nCatalogLoaded)
|
||||
return message;
|
||||
if (activeLanguageCode == I18N_DEFAULT_LANGUAGE_CODE)
|
||||
return message;
|
||||
|
||||
string key = "";
|
||||
if (i18n_catalog_get_string(i18nExactEnglishToKey, message, key)) {
|
||||
return i18n_lookup_key_with_fallback(key, message);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < i18nTemplateEnglish.length(); i++) {
|
||||
dictionary captures;
|
||||
if (!i18n_match_template(i18nTemplateEnglish[i], message, captures))
|
||||
continue;
|
||||
|
||||
string[] @captureKeys = captures.get_keys();
|
||||
if (@captureKeys !is null) {
|
||||
for (uint keyIndex = 0; keyIndex < captureKeys.length(); keyIndex++) {
|
||||
string captureKey = captureKeys[keyIndex];
|
||||
string captureValue = "";
|
||||
if (!i18n_catalog_get_string(captures, captureKey, captureValue))
|
||||
continue;
|
||||
captures.set(captureKey, i18n_translate_fragment_value(captureValue));
|
||||
}
|
||||
}
|
||||
|
||||
string localizedTemplate = i18n_lookup_key_with_fallback(i18nTemplateKeys[i], i18nTemplateEnglish[i]);
|
||||
return i18n_format_template(localizedTemplate, captures);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
string i18n_text(const string& in message) {
|
||||
return i18n_translate_speech_message(message);
|
||||
}
|
||||
|
||||
void i18n_translate_string_array_in_place(string[] &inout values) {
|
||||
for (uint i = 0; i < values.length(); i++) {
|
||||
values[i] = i18n_translate_speech_message(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool i18n_load_language(const string& in languageCode) {
|
||||
if (@i18nActiveCatalog is null)
|
||||
@i18nActiveCatalog = dictionary();
|
||||
|
||||
string normalized = i18n_trim_whitespace(languageCode);
|
||||
if (normalized == "")
|
||||
normalized = I18N_DEFAULT_LANGUAGE_CODE;
|
||||
|
||||
if (normalized == I18N_DEFAULT_LANGUAGE_CODE) {
|
||||
i18nActiveCatalog.clear();
|
||||
activeLanguageCode = I18N_DEFAULT_LANGUAGE_CODE;
|
||||
i18nCatalogLoaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
string catalogPath = I18N_LANGUAGE_DIRECTORY + "/" + normalized + ".ini";
|
||||
dictionary loadedCatalog;
|
||||
if (!i18n_load_catalog_file(catalogPath, loadedCatalog)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
i18nActiveCatalog.clear();
|
||||
string[] @loadedKeys = loadedCatalog.get_keys();
|
||||
if (@loadedKeys !is null) {
|
||||
for (uint i = 0; i < loadedKeys.length(); i++) {
|
||||
string key = loadedKeys[i];
|
||||
string value = "";
|
||||
if (!i18n_catalog_get_string(loadedCatalog, key, value))
|
||||
continue;
|
||||
i18nActiveCatalog.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
activeLanguageCode = normalized;
|
||||
i18nCatalogLoaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void i18n_save_language_preference(const string& in languageCode) {
|
||||
string code = i18n_trim_whitespace(languageCode);
|
||||
if (code == "")
|
||||
code = I18N_DEFAULT_LANGUAGE_CODE;
|
||||
|
||||
string content = I18N_LANGUAGE_PREF_KEY + "=" + code + "\n";
|
||||
i18n_write_file_text(i18n_get_pref_file_path(), content);
|
||||
}
|
||||
|
||||
string i18n_load_language_preference() {
|
||||
string data = "";
|
||||
if (!i18n_read_file_text(i18n_get_pref_file_path(), data))
|
||||
return "";
|
||||
|
||||
string[] lines = data.split("\n");
|
||||
for (uint i = 0; i < lines.length(); i++) {
|
||||
string line = lines[i];
|
||||
if (line.length() > 0 && line.substr(line.length() - 1) == "\r")
|
||||
line = line.substr(0, line.length() - 1);
|
||||
|
||||
string key = "";
|
||||
string value = "";
|
||||
if (!i18n_parse_catalog_line(line, key, value))
|
||||
continue;
|
||||
if (key == I18N_LANGUAGE_PREF_KEY)
|
||||
return i18n_trim_whitespace(value);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void i18n_get_available_languages(string[] &out languageCodes, string[] &out languageLabels) {
|
||||
languageCodes.resize(0);
|
||||
languageLabels.resize(0);
|
||||
|
||||
string[] @paths = glob(I18N_LANGUAGE_DIRECTORY + "/*.ini");
|
||||
if (@paths is null)
|
||||
return;
|
||||
|
||||
bool hasEnglish = false;
|
||||
|
||||
for (uint i = 0; i < paths.length(); i++) {
|
||||
string fileName = i18n_get_path_basename(paths[i]);
|
||||
string lowerFileName = fileName.lower();
|
||||
if (lowerFileName.length() >= 13 && lowerFileName.substr(lowerFileName.length() - 13) == ".template.ini")
|
||||
continue;
|
||||
if (fileName.length() < 5)
|
||||
continue;
|
||||
if (fileName.substr(fileName.length() - 4).lower() != ".ini")
|
||||
continue;
|
||||
|
||||
string code = fileName.substr(0, fileName.length() - 4);
|
||||
if (code == "")
|
||||
continue;
|
||||
|
||||
if (code.lower() == I18N_DEFAULT_LANGUAGE_CODE)
|
||||
hasEnglish = true;
|
||||
|
||||
dictionary tempCatalog;
|
||||
string label = code;
|
||||
if (i18n_load_catalog_file(paths[i], tempCatalog)) {
|
||||
string nativeName = "";
|
||||
if (i18n_catalog_get_string(tempCatalog, "meta.native_name", nativeName) && nativeName != "") {
|
||||
label = nativeName + " (" + code + ")";
|
||||
} else if (i18n_catalog_get_string(tempCatalog, "meta.name", nativeName) && nativeName != "") {
|
||||
label = nativeName + " (" + code + ")";
|
||||
}
|
||||
}
|
||||
|
||||
languageCodes.insert_last(code);
|
||||
languageLabels.insert_last(label);
|
||||
}
|
||||
|
||||
if (!hasEnglish) {
|
||||
languageCodes.insert_last(I18N_DEFAULT_LANGUAGE_CODE);
|
||||
languageLabels.insert_last(i18n_lookup_key_with_fallback("system.language.english_label", "English (en)"));
|
||||
}
|
||||
}
|
||||
|
||||
int i18n_find_language_index(const string[] @languageCodes, const string& in languageCode) {
|
||||
if (@languageCodes is null || languageCodes.length() == 0)
|
||||
return -1;
|
||||
|
||||
string target = i18n_trim_whitespace(languageCode).lower();
|
||||
if (target == "")
|
||||
return -1;
|
||||
|
||||
for (uint i = 0; i < languageCodes.length(); i++) {
|
||||
if (languageCodes[i].lower() == target)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int i18n_run_language_selection_menu(const string[] @languageCodes, const string[] @languageLabels,
|
||||
int defaultIndex = 0) {
|
||||
if (@languageCodes is null || @languageLabels is null)
|
||||
return -1;
|
||||
if (languageCodes.length() == 0 || languageLabels.length() == 0)
|
||||
return -1;
|
||||
|
||||
int selection = defaultIndex;
|
||||
if (selection < 0 || selection >= int(languageLabels.length()))
|
||||
selection = 0;
|
||||
|
||||
string prompt = tr("system.language.select_prompt");
|
||||
if (prompt.length() > 0 && prompt.substr(prompt.length() - 1) == ".") {
|
||||
prompt = prompt.substr(0, prompt.length() - 1);
|
||||
}
|
||||
if (prompt != "") {
|
||||
speak_with_history(prompt + " " + languageLabels[selection], true);
|
||||
} else {
|
||||
speak_with_history(languageLabels[selection], true);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
handle_global_volume_keys();
|
||||
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
play_menu_move_sound();
|
||||
selection++;
|
||||
if (selection >= int(languageLabels.length()))
|
||||
selection = 0;
|
||||
speak_with_history(languageLabels[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_UP)) {
|
||||
play_menu_move_sound();
|
||||
selection--;
|
||||
if (selection < 0)
|
||||
selection = languageLabels.length() - 1;
|
||||
speak_with_history(languageLabels[selection], true);
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_RETURN)) {
|
||||
play_menu_select_sound();
|
||||
return selection;
|
||||
}
|
||||
|
||||
if (key_pressed(KEY_ESCAPE)) {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
bool i18n_load_english_catalog() {
|
||||
if (@i18nEnglishCatalog is null)
|
||||
@i18nEnglishCatalog = dictionary();
|
||||
|
||||
if (!i18n_load_catalog_file(I18N_ENGLISH_CATALOG_PATH, i18nEnglishCatalog)) {
|
||||
i18nEnglishCatalog.clear();
|
||||
i18nEnglishCatalog.set("system.language.select_prompt", "Select your language.");
|
||||
i18nEnglishCatalog.set("system.language.selected", "Language set to {language}.");
|
||||
i18nEnglishCatalog.set("system.ui.window_title", "Draugnorak");
|
||||
}
|
||||
|
||||
i18n_rebuild_indexes();
|
||||
return i18nEnglishCatalog.get_size() > 0;
|
||||
}
|
||||
|
||||
void i18n_init() {
|
||||
if (i18nInitialized)
|
||||
return;
|
||||
i18nInitialized = true;
|
||||
|
||||
i18n_load_english_catalog();
|
||||
speech_history_set_message_transform_callback(i18n_translate_speech_message);
|
||||
ui_set_text_transform_callback(i18n_translate_speech_message);
|
||||
|
||||
string[] languageCodes;
|
||||
string[] languageLabels;
|
||||
i18n_get_available_languages(languageCodes, languageLabels);
|
||||
|
||||
string preferredLanguage = i18n_load_language_preference();
|
||||
int preferredIndex = i18n_find_language_index(languageCodes, preferredLanguage);
|
||||
bool promptedForLanguage = false;
|
||||
|
||||
if (preferredIndex < 0) {
|
||||
promptedForLanguage = true;
|
||||
int englishIndex = i18n_find_language_index(languageCodes, I18N_DEFAULT_LANGUAGE_CODE);
|
||||
if (englishIndex < 0)
|
||||
englishIndex = 0;
|
||||
preferredIndex = i18n_run_language_selection_menu(languageCodes, languageLabels, englishIndex);
|
||||
}
|
||||
|
||||
string chosenLanguage = I18N_DEFAULT_LANGUAGE_CODE;
|
||||
if (preferredIndex >= 0 && preferredIndex < int(languageCodes.length())) {
|
||||
chosenLanguage = languageCodes[preferredIndex];
|
||||
}
|
||||
|
||||
if (!i18n_load_language(chosenLanguage)) {
|
||||
i18n_load_language(I18N_DEFAULT_LANGUAGE_CODE);
|
||||
chosenLanguage = I18N_DEFAULT_LANGUAGE_CODE;
|
||||
promptedForLanguage = true;
|
||||
}
|
||||
|
||||
i18n_save_language_preference(chosenLanguage);
|
||||
|
||||
if (promptedForLanguage) {
|
||||
dictionary args;
|
||||
string selectedLabel = chosenLanguage;
|
||||
int selectedLanguageIndex = i18n_find_language_index(languageCodes, chosenLanguage);
|
||||
if (selectedLanguageIndex >= 0 && selectedLanguageIndex < int(languageLabels.length())) {
|
||||
selectedLabel = languageLabels[selectedLanguageIndex];
|
||||
}
|
||||
args.set("language", selectedLabel);
|
||||
speak_with_history(trf("system.language.selected", args), true);
|
||||
}
|
||||
}
|
||||
+23
-44
@@ -94,38 +94,14 @@ void clamp_arrows_to_quiver_limit() {
|
||||
|
||||
set_personal_count(ITEM_ARROWS, maxArrows);
|
||||
if (maxArrows == 0) {
|
||||
speak_with_history("You need a quiver to carry arrows.", true);
|
||||
speak_need_quiver_for_arrows();
|
||||
} else {
|
||||
speak_with_history("You can only carry " + maxArrows + " arrows with your current quivers.", true);
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
return "Unknown";
|
||||
return get_base_equipment_name(equip_type);
|
||||
}
|
||||
|
||||
bool equipment_available(int equip_type) {
|
||||
@@ -481,7 +457,9 @@ void activate_quick_slot(int slot_index) {
|
||||
int count = get_item_count_for_type(item_type);
|
||||
speak_with_history(get_item_count_label(item_type, count) + ".", true);
|
||||
} else {
|
||||
speak_with_history("No item bound to slot " + slot_index + ".", true);
|
||||
dictionary args;
|
||||
args.set("slot", slot_index);
|
||||
speak_with_history(trf("system.quick_slot.no_item_bound", args), true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -556,34 +534,35 @@ string format_favor(double value) {
|
||||
|
||||
string get_equipped_weapon_name() {
|
||||
if (spear_equipped)
|
||||
return "Spear";
|
||||
return get_base_equipment_name(EQUIP_SPEAR);
|
||||
if (axe_equipped)
|
||||
return "Stone Axe";
|
||||
return get_base_equipment_name(EQUIP_AXE);
|
||||
if (sling_equipped)
|
||||
return "Sling";
|
||||
return get_base_equipment_name(EQUIP_SLING);
|
||||
if (bow_equipped)
|
||||
return "Bow";
|
||||
return get_base_equipment_name(EQUIP_BOW);
|
||||
if (fishing_pole_equipped)
|
||||
return "Fishing Pole";
|
||||
return "None";
|
||||
return get_base_equipment_name(EQUIP_FISHING_POLE);
|
||||
return i18n_lookup_key_with_fallback("system.equipment.name.none", "None");
|
||||
}
|
||||
|
||||
string get_speed_status() {
|
||||
string status = "";
|
||||
int rune_bonus = get_total_rune_walk_speed_bonus();
|
||||
|
||||
if (blessing_speed_active) {
|
||||
status = "blessed";
|
||||
} else if (equipped_feet == EQUIP_MOCCASINS && rune_bonus > 0) {
|
||||
status = "boosted by moccasins and runes";
|
||||
} else if (equipped_feet == EQUIP_MOCCASINS) {
|
||||
status = "boosted by moccasins";
|
||||
} else if (rune_bonus > 0) {
|
||||
status = "boosted by runes";
|
||||
} else {
|
||||
status = "normal";
|
||||
return i18n_lookup_key_with_fallback("system.character.speed.blessed", "blessed");
|
||||
}
|
||||
return status;
|
||||
if (equipped_feet == EQUIP_MOCCASINS && rune_bonus > 0) {
|
||||
return i18n_lookup_key_with_fallback(
|
||||
"system.character.speed.boosted_moccasins_and_runes", "boosted by moccasins and runes");
|
||||
}
|
||||
if (equipped_feet == EQUIP_MOCCASINS) {
|
||||
return i18n_lookup_key_with_fallback("system.character.speed.boosted_moccasins", "boosted by moccasins");
|
||||
}
|
||||
if (rune_bonus > 0) {
|
||||
return i18n_lookup_key_with_fallback("system.character.speed.boosted_runes", "boosted by runes");
|
||||
}
|
||||
return i18n_lookup_key_with_fallback("system.character.speed.normal", "normal");
|
||||
}
|
||||
|
||||
void cleanup_equipment_after_inventory_change() {
|
||||
|
||||
@@ -37,7 +37,7 @@ void check_inventory_keys(int x) {
|
||||
run_inventory_root_menu();
|
||||
} else {
|
||||
if (in_base && world_storages.length() == 0) {
|
||||
speak_with_history("No storage built.", true);
|
||||
speak_with_history(tr("system.storage.no_storage_built"), true);
|
||||
}
|
||||
run_inventory_menu(false);
|
||||
}
|
||||
|
||||
+28
-6
@@ -281,20 +281,20 @@ int get_smoked_fish_yield(int weight) {
|
||||
// Item metadata lookups
|
||||
string get_item_label(int item_type) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return "items";
|
||||
return item_registry[item_type].name;
|
||||
return i18n_lookup_key_with_fallback("system.item.label.items", "items");
|
||||
return i18n_translate_speech_message(item_registry[item_type].name);
|
||||
}
|
||||
|
||||
string get_item_label_singular(int item_type) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return "item";
|
||||
return item_registry[item_type].singular;
|
||||
return i18n_lookup_key_with_fallback("system.item.label.item", "item");
|
||||
return i18n_translate_speech_message(item_registry[item_type].singular);
|
||||
}
|
||||
|
||||
string get_item_display_name(int item_type) {
|
||||
if (item_type < 0 || item_type >= ITEM_COUNT)
|
||||
return "Unknown";
|
||||
return item_registry[item_type].display_name;
|
||||
return i18n_lookup_key_with_fallback("system.item.label.unknown", "Unknown");
|
||||
return i18n_translate_speech_message(item_registry[item_type].display_name);
|
||||
}
|
||||
|
||||
double get_item_favor_value(int item_type) {
|
||||
@@ -311,6 +311,28 @@ string get_item_label_for_count(int item_type, int count) {
|
||||
return get_item_label(item_type);
|
||||
}
|
||||
|
||||
string format_cant_carry_any_more_label(const string& in item_label) {
|
||||
dictionary args;
|
||||
args.set("item", item_label);
|
||||
return trf("system.inventory.cant_carry_any_more_item", args);
|
||||
}
|
||||
|
||||
void speak_cant_carry_any_more_label(const string& in item_label) {
|
||||
speak_with_history(format_cant_carry_any_more_label(item_label), true);
|
||||
}
|
||||
|
||||
void speak_cant_carry_any_more_item(int item_type) {
|
||||
speak_cant_carry_any_more_label(get_item_label(item_type));
|
||||
}
|
||||
|
||||
string get_need_quiver_for_arrows_message() {
|
||||
return tr("system.inventory.need_quiver_for_arrows");
|
||||
}
|
||||
|
||||
void speak_need_quiver_for_arrows() {
|
||||
speak_with_history(get_need_quiver_for_arrows_message(), true);
|
||||
}
|
||||
|
||||
// Encode runed item info into a negative item type
|
||||
// Format: -1000 - (equip_type * 10) - rune_type
|
||||
// This allows us to extract both equip_type and rune_type from a single int
|
||||
|
||||
@@ -260,6 +260,7 @@ void run_action_menu(int x) {
|
||||
options.insert_last("Check fishing pole");
|
||||
action_types.insert_last(7);
|
||||
}
|
||||
i18n_translate_string_array_in_place(options);
|
||||
string filter_text = "";
|
||||
int[] filtered_indices;
|
||||
string[] filtered_options;
|
||||
|
||||
@@ -53,6 +53,7 @@ void run_base_info_menu() {
|
||||
} else {
|
||||
options.insert_last("Stable not built");
|
||||
}
|
||||
i18n_translate_string_array_in_place(options);
|
||||
string filter_text = "";
|
||||
int[] filtered_indices;
|
||||
string[] filtered_options;
|
||||
|
||||
@@ -3,16 +3,18 @@
|
||||
|
||||
bool run_pet_abandon_confirm_menu() {
|
||||
if (!petActive) {
|
||||
speak_with_history("No pet.", true);
|
||||
speak_with_history(tr("system.character.pet.no_pet"), true);
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] options;
|
||||
options.insert_last("No");
|
||||
options.insert_last("Yes");
|
||||
options.insert_last(tr("system.option.no"));
|
||||
options.insert_last(tr("system.option.yes"));
|
||||
int selection = 0;
|
||||
|
||||
speak_with_history("Really abandon your pet? " + options[selection], true);
|
||||
dictionary promptArgs;
|
||||
promptArgs.set("option", options[selection]);
|
||||
speak_with_history(trf("system.character.pet.abandon_confirm", promptArgs), true);
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
@@ -20,7 +22,7 @@ bool run_pet_abandon_confirm_menu() {
|
||||
return false;
|
||||
}
|
||||
if (key_pressed(KEY_ESCAPE)) {
|
||||
speak_with_history("Canceled.", true);
|
||||
speak_with_history(tr("system.menu.canceled"), true);
|
||||
return false;
|
||||
}
|
||||
if (key_pressed(KEY_DOWN)) {
|
||||
@@ -42,7 +44,7 @@ bool run_pet_abandon_confirm_menu() {
|
||||
if (selection == 1) {
|
||||
return abandon_pet();
|
||||
}
|
||||
speak_with_history("Canceled.", true);
|
||||
speak_with_history(tr("system.menu.canceled"), true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -55,63 +57,98 @@ void run_character_info_menu() {
|
||||
string[] missing_slots;
|
||||
|
||||
if (equipped_head == EQUIP_HAT)
|
||||
equipped_clothing.insert_last("Skin Hat");
|
||||
equipped_clothing.insert_last(get_base_equipment_name(EQUIP_HAT));
|
||||
else
|
||||
missing_slots.insert_last("head");
|
||||
missing_slots.insert_last(tr("system.character.slot.head"));
|
||||
if (equipped_torso == EQUIP_TUNIC)
|
||||
equipped_clothing.insert_last("Skin Tunic");
|
||||
equipped_clothing.insert_last(get_base_equipment_name(EQUIP_TUNIC));
|
||||
else
|
||||
missing_slots.insert_last("torso");
|
||||
missing_slots.insert_last(tr("system.character.slot.torso"));
|
||||
if (equipped_arms == EQUIP_POUCH)
|
||||
equipped_clothing.insert_last("Skin Pouch");
|
||||
equipped_clothing.insert_last(get_base_equipment_name(EQUIP_POUCH));
|
||||
else if (equipped_arms == EQUIP_BACKPACK)
|
||||
equipped_clothing.insert_last("Backpack");
|
||||
equipped_clothing.insert_last(get_base_equipment_name(EQUIP_BACKPACK));
|
||||
else
|
||||
missing_slots.insert_last("arms");
|
||||
missing_slots.insert_last(tr("system.character.slot.arms"));
|
||||
if (equipped_hands == EQUIP_GLOVES)
|
||||
equipped_clothing.insert_last("Skin Gloves");
|
||||
equipped_clothing.insert_last(get_base_equipment_name(EQUIP_GLOVES));
|
||||
else
|
||||
missing_slots.insert_last("hands");
|
||||
missing_slots.insert_last(tr("system.character.slot.hands"));
|
||||
if (equipped_legs == EQUIP_PANTS)
|
||||
equipped_clothing.insert_last("Skin Pants");
|
||||
equipped_clothing.insert_last(get_base_equipment_name(EQUIP_PANTS));
|
||||
else
|
||||
missing_slots.insert_last("legs");
|
||||
missing_slots.insert_last(tr("system.character.slot.legs"));
|
||||
if (equipped_feet == EQUIP_MOCCASINS)
|
||||
equipped_clothing.insert_last("Moccasins");
|
||||
equipped_clothing.insert_last(get_base_equipment_name(EQUIP_MOCCASINS));
|
||||
else
|
||||
missing_slots.insert_last("feet");
|
||||
missing_slots.insert_last(tr("system.character.slot.feet"));
|
||||
|
||||
string[] options;
|
||||
int petOptionIndex = -1;
|
||||
if (player_name != "") {
|
||||
string sex_label = (player_sex == SEX_FEMALE) ? "Female" : "Male";
|
||||
options.insert_last("Name " + player_name + ". Sex " + sex_label + ".");
|
||||
string sex_label = (player_sex == SEX_FEMALE) ? tr("system.sex.female") : tr("system.sex.male");
|
||||
dictionary nameArgs;
|
||||
nameArgs.set("name", player_name);
|
||||
nameArgs.set("sex", sex_label);
|
||||
options.insert_last(trf("system.character.info.name_sex", nameArgs));
|
||||
} else {
|
||||
options.insert_last("Name unknown.");
|
||||
options.insert_last(tr("system.character.info.name_unknown"));
|
||||
}
|
||||
options.insert_last("Health " + player_health + " of " + max_health + ".");
|
||||
options.insert_last("Weapon " + get_equipped_weapon_name() + ".");
|
||||
|
||||
dictionary healthArgs;
|
||||
healthArgs.set("health", player_health);
|
||||
healthArgs.set("max", max_health);
|
||||
options.insert_last(trf("system.character.info.health", healthArgs));
|
||||
|
||||
dictionary weaponArgs;
|
||||
weaponArgs.set("weapon", get_equipped_weapon_name());
|
||||
options.insert_last(trf("system.character.info.weapon", weaponArgs));
|
||||
|
||||
if (equipped_clothing.length() > 0) {
|
||||
options.insert_last("Clothing equipped: " + join_string_list(equipped_clothing) + ".");
|
||||
dictionary clothingArgs;
|
||||
clothingArgs.set("items", join_string_list(equipped_clothing));
|
||||
options.insert_last(trf("system.character.info.clothing_equipped", clothingArgs));
|
||||
} else {
|
||||
options.insert_last("No clothing equipped.");
|
||||
options.insert_last(tr("system.character.info.no_clothing"));
|
||||
}
|
||||
|
||||
if (missing_slots.length() > 0) {
|
||||
options.insert_last("Missing " + join_string_list(missing_slots) + ".");
|
||||
dictionary missingArgs;
|
||||
missingArgs.set("slots", join_string_list(missing_slots));
|
||||
options.insert_last(trf("system.character.info.missing", missingArgs));
|
||||
}
|
||||
options.insert_last("Favor " + format_favor(favor) + ".");
|
||||
options.insert_last("Speed " + get_speed_status() + ".");
|
||||
|
||||
dictionary favorArgs;
|
||||
favorArgs.set("favor", format_favor(favor));
|
||||
options.insert_last(trf("system.character.info.favor", favorArgs));
|
||||
|
||||
dictionary speedArgs;
|
||||
speedArgs.set("status", get_speed_status());
|
||||
options.insert_last(trf("system.character.info.speed", speedArgs));
|
||||
|
||||
if (petActive) {
|
||||
string petInfo = "Pet " + get_pet_display_name() + ". " + petHealth + " health of " + PET_HEALTH_MAX + ".";
|
||||
petInfo += " Loyalty " + petLoyalty + " of " + PET_LOYALTY_MAX + ".";
|
||||
dictionary petArgs;
|
||||
petArgs.set("pet", get_pet_display_name());
|
||||
petArgs.set("health", petHealth);
|
||||
petArgs.set("max_health", PET_HEALTH_MAX);
|
||||
petArgs.set("loyalty", petLoyalty);
|
||||
petArgs.set("max_loyalty", PET_LOYALTY_MAX);
|
||||
string petInfo = trf("system.character.info.pet", petArgs);
|
||||
|
||||
if (petKnockoutHoursRemaining > 0) {
|
||||
string hourLabel = (petKnockoutHoursRemaining == 1) ? "hour" : "hours";
|
||||
petInfo += " Knocked out. " + petKnockoutHoursRemaining + " " + hourLabel + " remaining.";
|
||||
dictionary petKnockoutArgs;
|
||||
petKnockoutArgs.set("hours", petKnockoutHoursRemaining);
|
||||
if (petKnockoutHoursRemaining == 1) {
|
||||
petKnockoutArgs.set("hour_label", tr("system.character.word.hour"));
|
||||
} else {
|
||||
petKnockoutArgs.set("hour_label", tr("system.character.word.hours"));
|
||||
}
|
||||
petInfo += " " + trf("system.character.info.pet_knocked_out", petKnockoutArgs);
|
||||
}
|
||||
options.insert_last(petInfo);
|
||||
petOptionIndex = options.length() - 1;
|
||||
} else {
|
||||
options.insert_last("Pet none.");
|
||||
options.insert_last(tr("system.character.info.pet_none"));
|
||||
}
|
||||
|
||||
int selection = 0;
|
||||
@@ -120,9 +157,11 @@ void run_character_info_menu() {
|
||||
string[] filtered_options;
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
if (filtered_options.length() == 0) {
|
||||
speak_with_history("Character info. No options.", true);
|
||||
speak_with_history(tr("system.character.menu.no_options"), true);
|
||||
} else {
|
||||
speak_with_history("Character info. " + filtered_options[selection], true);
|
||||
dictionary promptArgs;
|
||||
promptArgs.set("option", filtered_options[selection]);
|
||||
speak_with_history(trf("system.character.menu.prompt", promptArgs), true);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
@@ -131,7 +170,7 @@ void run_character_info_menu() {
|
||||
return;
|
||||
}
|
||||
if (key_pressed(KEY_ESCAPE)) {
|
||||
speak_with_history("Closed.", true);
|
||||
speak_with_history(tr("system.menu.closed"), true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -140,9 +179,11 @@ void run_character_info_menu() {
|
||||
if (filter_changed) {
|
||||
if (filtered_options.length() == 0) {
|
||||
if (filter_text.length() > 0) {
|
||||
speak_with_history("No matches for " + filter_text + ".", true);
|
||||
dictionary filterArgs;
|
||||
filterArgs.set("arg1", filter_text);
|
||||
speak_with_history(trf("system.menu.no_matches", filterArgs), true);
|
||||
} else {
|
||||
speak_with_history("No options.", true);
|
||||
speak_with_history(tr("system.menu.no_options"), true);
|
||||
}
|
||||
} else {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
@@ -176,8 +217,9 @@ void run_character_info_menu() {
|
||||
int optionIndex = filtered_indices[selection];
|
||||
if (optionIndex == petOptionIndex && petActive) {
|
||||
if (is_pet_knocked_out()) {
|
||||
speak_with_history(
|
||||
"Your " + get_pet_display_name() + " is unconscious. You can't abandon it right now.", true);
|
||||
dictionary args;
|
||||
args.set("pet", get_pet_display_name());
|
||||
speak_with_history(trf("system.character.pet.unconscious_cannot_abandon", args), true);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,12 @@ bool is_runed_item_equipped(int equip_type, int rune_type) {
|
||||
return get_equipped_rune_for_slot(equip_type) == rune_type;
|
||||
}
|
||||
|
||||
string get_equipment_menu_equipped_suffix(bool equipped) {
|
||||
if (!equipped)
|
||||
return "";
|
||||
return i18n_lookup_key_with_fallback("system.equipment.menu.equipped_suffix", " (equipped)");
|
||||
}
|
||||
|
||||
void run_equipment_menu() {
|
||||
speak_with_history("Equipment menu.", true);
|
||||
|
||||
@@ -64,74 +70,74 @@ void run_equipment_menu() {
|
||||
|
||||
// Add unruned items
|
||||
if (get_personal_count(ITEM_SPEARS) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_SPEAR, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Spear" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_SPEAR, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_SPEAR, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_SPEAR);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_SLINGS) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_SLING, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Sling" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_SLING, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_SLING, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_SLING);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_AXES) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_AXE, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Stone Axe" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_AXE, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_AXE, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_AXE);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_BOWS) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_BOW, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Bow" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_BOW, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_BOW, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_BOW);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_FISHING_POLES) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_FISHING_POLE, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Fishing Pole" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_FISHING_POLE, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_FISHING_POLE, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_FISHING_POLE);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_SKIN_HATS) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_HAT, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Skin Hat" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_HAT, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_HAT, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_HAT);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_SKIN_GLOVES) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_GLOVES, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Skin Gloves" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_GLOVES, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_GLOVES, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_GLOVES);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_SKIN_PANTS) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_PANTS, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Skin Pants" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_PANTS, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_PANTS, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_PANTS);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_SKIN_TUNICS) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_TUNIC, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Skin Tunic" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_TUNIC, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_TUNIC, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_TUNIC);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_MOCCASINS) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_MOCCASINS, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Moccasins" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_MOCCASINS, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_MOCCASINS, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_MOCCASINS);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_SKIN_POUCHES) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_POUCH, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Skin Pouch" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_POUCH, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_POUCH, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_POUCH);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
if (get_personal_count(ITEM_BACKPACKS) > 0) {
|
||||
string status = is_runed_item_equipped(EQUIP_BACKPACK, RUNE_NONE) ? " (equipped)" : "";
|
||||
options.insert_last("Backpack" + status);
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(EQUIP_BACKPACK, RUNE_NONE));
|
||||
options.insert_last(get_full_equipment_name(EQUIP_BACKPACK, RUNE_NONE) + status);
|
||||
equipment_types.insert_last(EQUIP_BACKPACK);
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
@@ -148,7 +154,7 @@ void run_equipment_menu() {
|
||||
if (count <= 0)
|
||||
continue;
|
||||
string name = get_full_equipment_name(equip_type, rune_type);
|
||||
string status = is_runed_item_equipped(equip_type, rune_type) ? " (equipped)" : "";
|
||||
string status = get_equipment_menu_equipped_suffix(is_runed_item_equipped(equip_type, rune_type));
|
||||
options.insert_last(name + status);
|
||||
equipment_types.insert_last(equip_type);
|
||||
rune_types.insert_last(rune_type);
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
// Personal inventory menu system
|
||||
// Functions for displaying and managing personal inventory
|
||||
|
||||
void speak_inventory_menu_prompt(const string& in option_label) {
|
||||
dictionary args;
|
||||
args.set("option", option_label);
|
||||
speak_with_history(trf("system.inventory.menu.prompt", args), true);
|
||||
}
|
||||
|
||||
void speak_menu_no_matches(const string& in filter_text) {
|
||||
dictionary args;
|
||||
args.set("arg1", filter_text);
|
||||
speak_with_history(trf("system.menu.no_matches", args), true);
|
||||
}
|
||||
|
||||
void build_personal_inventory_options(string[] @options, int[] @item_types) {
|
||||
options.resize(0);
|
||||
item_types.resize(0);
|
||||
@@ -78,10 +90,9 @@ void show_inventory() {
|
||||
}
|
||||
|
||||
void run_inventory_root_menu() {
|
||||
speak_with_history("Inventory menu.", true);
|
||||
|
||||
int selection = 0;
|
||||
string[] options = {"Personal inventory", "Base storage"};
|
||||
string[] options = {tr("system.inventory.option.personal"), tr("system.inventory.option.base_storage")};
|
||||
speak_inventory_menu_prompt(options[selection]);
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
@@ -89,7 +100,7 @@ void run_inventory_root_menu() {
|
||||
return;
|
||||
}
|
||||
if (key_pressed(KEY_ESCAPE)) {
|
||||
speak_with_history("Closed.", true);
|
||||
speak_with_history(tr("system.menu.closed"), true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -121,8 +132,6 @@ void run_inventory_root_menu() {
|
||||
}
|
||||
|
||||
void run_inventory_menu(bool allow_deposit) {
|
||||
speak_with_history("Inventory menu.", true);
|
||||
|
||||
int selection = 0;
|
||||
string[] options;
|
||||
int[] item_types;
|
||||
@@ -131,6 +140,11 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
int[] filtered_indices;
|
||||
string[] filtered_options;
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
if (filtered_options.length() == 0) {
|
||||
speak_with_history(tr("system.inventory.menu.no_options"), true);
|
||||
} else {
|
||||
speak_inventory_menu_prompt(filtered_options[selection]);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
@@ -138,7 +152,7 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
return;
|
||||
}
|
||||
if (key_pressed(KEY_ESCAPE)) {
|
||||
speak_with_history("Closed.", true);
|
||||
speak_with_history(tr("system.menu.closed"), true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -147,9 +161,9 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
if (filter_changed) {
|
||||
if (filtered_options.length() == 0) {
|
||||
if (filter_text.length() > 0) {
|
||||
speak_with_history("No matches for " + filter_text + ".", true);
|
||||
speak_menu_no_matches(filter_text);
|
||||
} else {
|
||||
speak_with_history("No options.", true);
|
||||
speak_with_history(tr("system.menu.no_options"), true);
|
||||
}
|
||||
} else {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
@@ -182,7 +196,10 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
if (slot_index >= 0 && slot_index < int(item_count_slots.length())) {
|
||||
item_count_slots[slot_index] = item_type;
|
||||
string name = get_item_count_binding_name(item_type);
|
||||
speak_with_history(name + " count set to slot " + slot_index + ".", true);
|
||||
dictionary args;
|
||||
args.set("name", name);
|
||||
args.set("slot", slot_index);
|
||||
speak_with_history(trf("system.inventory.count_set_to_slot", args), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +214,7 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
if (filtered_options.length() > 0) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
} else if (filter_text.length() > 0) {
|
||||
speak_with_history("No matches for " + filter_text + ".", true);
|
||||
speak_menu_no_matches(filter_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,7 +230,7 @@ void run_inventory_menu(bool allow_deposit) {
|
||||
if (filtered_options.length() > 0) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
} else if (filter_text.length() > 0) {
|
||||
speak_with_history("No matches for " + filter_text + ".", true);
|
||||
speak_menu_no_matches(filter_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+46
-28
@@ -1,6 +1,18 @@
|
||||
// Base storage menu system
|
||||
// Functions for interacting with base storage (deposit/withdraw items)
|
||||
|
||||
void speak_storage_menu_prompt(const string& in option_label) {
|
||||
dictionary args;
|
||||
args.set("option", option_label);
|
||||
speak_with_history(trf("system.storage.menu.prompt", args), true);
|
||||
}
|
||||
|
||||
void speak_storage_menu_no_matches(const string& in filter_text) {
|
||||
dictionary args;
|
||||
args.set("arg1", filter_text);
|
||||
speak_with_history(trf("system.menu.no_matches", args), true);
|
||||
}
|
||||
|
||||
void move_small_game_to_storage(int amount) {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
string game_type = "small game";
|
||||
@@ -31,8 +43,11 @@ void move_fish_to_personal(int amount) {
|
||||
move_fish_weights_to_personal(amount);
|
||||
}
|
||||
|
||||
int prompt_transfer_amount(const string prompt, int max_amount) {
|
||||
string input = ui_input_box("Inventory", prompt + " (max " + max_amount + ")", "");
|
||||
int prompt_transfer_amount(const string prompt_label, int max_amount) {
|
||||
dictionary args;
|
||||
args.set("prompt", prompt_label);
|
||||
args.set("max", max_amount);
|
||||
string input = ui_input_box(tr("system.storage.window_title"), trf("system.storage.transfer_prompt", args), "");
|
||||
int amount = parse_int(input);
|
||||
if (amount <= 0)
|
||||
return 0;
|
||||
@@ -51,27 +66,27 @@ void deposit_item(int item_type) {
|
||||
cleanup_equipment_after_inventory_change();
|
||||
speak_with_history("Deposited " + name + ".", true);
|
||||
} else {
|
||||
speak_with_history("Nothing to deposit.", true);
|
||||
speak_with_history(tr("system.storage.nothing_to_deposit"), true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Handle legacy -2 marker (shouldn't happen anymore but keep for safety)
|
||||
if (item_type == -2) {
|
||||
speak_with_history("Runed items cannot be deposited into storage.", true);
|
||||
speak_with_history(tr("system.storage.runed_cannot_deposit"), true);
|
||||
return;
|
||||
}
|
||||
int available = get_personal_count(item_type);
|
||||
if (available <= 0) {
|
||||
speak_with_history("Nothing to deposit.", true);
|
||||
speak_with_history(tr("system.storage.nothing_to_deposit"), true);
|
||||
return;
|
||||
}
|
||||
int capacity = get_storage_stack_limit() - get_storage_count(item_type);
|
||||
if (capacity <= 0) {
|
||||
speak_with_history("Storage for that item is full.", true);
|
||||
speak_with_history(tr("system.storage.item_full"), true);
|
||||
return;
|
||||
}
|
||||
int max_transfer = (available < capacity) ? available : capacity;
|
||||
int amount = prompt_transfer_amount("Deposit how many?", max_transfer);
|
||||
int amount = prompt_transfer_amount(tr("system.storage.deposit_how_many"), max_transfer);
|
||||
if (amount <= 0)
|
||||
return;
|
||||
|
||||
@@ -98,7 +113,7 @@ void deposit_item_max(int item_type) {
|
||||
decode_runed_item_type(item_type, equip_type, rune_type);
|
||||
int personal = get_runed_item_count(equip_type, rune_type);
|
||||
if (personal <= 0) {
|
||||
speak_with_history("Nothing to deposit.", true);
|
||||
speak_with_history(tr("system.storage.nothing_to_deposit"), true);
|
||||
return;
|
||||
}
|
||||
int count = 0;
|
||||
@@ -113,18 +128,18 @@ void deposit_item_max(int item_type) {
|
||||
}
|
||||
// Handle legacy -2 marker
|
||||
if (item_type == -2) {
|
||||
speak_with_history("Runed items cannot be deposited into storage.", true);
|
||||
speak_with_history(tr("system.storage.runed_cannot_deposit"), true);
|
||||
return;
|
||||
}
|
||||
int available = get_personal_count(item_type);
|
||||
if (available <= 0) {
|
||||
speak_with_history("Nothing to deposit.", true);
|
||||
speak_with_history(tr("system.storage.nothing_to_deposit"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
int capacity = get_storage_stack_limit() - get_storage_count(item_type);
|
||||
if (capacity <= 0) {
|
||||
speak_with_history("Storage for that item is full.", true);
|
||||
speak_with_history(tr("system.storage.item_full"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -155,31 +170,31 @@ void withdraw_item(int item_type) {
|
||||
string name = "Runed " + get_base_equipment_name(equip_type) + " of " + get_rune_effect_name(rune_type);
|
||||
speak_with_history("Withdrew " + name + ".", true);
|
||||
} else {
|
||||
speak_with_history("Nothing to withdraw.", true);
|
||||
speak_with_history(tr("system.storage.nothing_to_withdraw"), true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int available = get_storage_count(item_type);
|
||||
if (available <= 0) {
|
||||
speak_with_history("Nothing to withdraw.", true);
|
||||
speak_with_history(tr("system.storage.nothing_to_withdraw"), true);
|
||||
return;
|
||||
}
|
||||
int capacity = 0;
|
||||
if (item_type == ITEM_ARROWS) {
|
||||
capacity = get_arrow_limit() - get_personal_count(ITEM_ARROWS);
|
||||
if (capacity <= 0) {
|
||||
speak_with_history("You can't carry any more arrows.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_ARROWS);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
capacity = get_personal_stack_limit() - get_personal_count(item_type);
|
||||
}
|
||||
if (capacity <= 0) {
|
||||
speak_with_history("You can't carry any more " + get_item_label(item_type) + ".", true);
|
||||
speak_cant_carry_any_more_item(item_type);
|
||||
return;
|
||||
}
|
||||
int max_transfer = (available < capacity) ? available : capacity;
|
||||
int amount = prompt_transfer_amount("Withdraw how many?", max_transfer);
|
||||
int amount = prompt_transfer_amount(tr("system.storage.withdraw_how_many"), max_transfer);
|
||||
if (amount <= 0)
|
||||
return;
|
||||
|
||||
@@ -205,7 +220,7 @@ void withdraw_item_max(int item_type) {
|
||||
decode_runed_item_type(item_type, equip_type, rune_type);
|
||||
int stored = get_stored_runed_item_count(equip_type, rune_type);
|
||||
if (stored <= 0) {
|
||||
speak_with_history("Nothing to withdraw.", true);
|
||||
speak_with_history(tr("system.storage.nothing_to_withdraw"), true);
|
||||
return;
|
||||
}
|
||||
int count = 0;
|
||||
@@ -219,7 +234,7 @@ void withdraw_item_max(int item_type) {
|
||||
}
|
||||
int available = get_storage_count(item_type);
|
||||
if (available <= 0) {
|
||||
speak_with_history("Nothing to withdraw.", true);
|
||||
speak_with_history(tr("system.storage.nothing_to_withdraw"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -229,7 +244,7 @@ void withdraw_item_max(int item_type) {
|
||||
personalLimit = get_arrow_limit();
|
||||
currentPersonal = get_personal_count(ITEM_ARROWS);
|
||||
if (personalLimit <= 0) {
|
||||
speak_with_history("You need a quiver to carry arrows.", true);
|
||||
speak_need_quiver_for_arrows();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -239,7 +254,7 @@ void withdraw_item_max(int item_type) {
|
||||
int space = personalLimit - currentPersonal;
|
||||
|
||||
if (space <= 0) {
|
||||
speak_with_history("Can't carry any more.", true);
|
||||
speak_cant_carry_any_more_item(item_type);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -293,12 +308,10 @@ void build_storage_inventory_options(string[] @options, int[] @item_types) {
|
||||
|
||||
void run_storage_menu() {
|
||||
if (world_storages.length() == 0) {
|
||||
speak_with_history("No storage built.", true);
|
||||
speak_with_history(tr("system.storage.no_storage_built"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
speak_with_history("Base storage.", true);
|
||||
|
||||
int selection = 0;
|
||||
string[] options;
|
||||
int[] item_types;
|
||||
@@ -307,6 +320,11 @@ void run_storage_menu() {
|
||||
int[] filtered_indices;
|
||||
string[] filtered_options;
|
||||
apply_menu_filter(filter_text, options, filtered_indices, filtered_options);
|
||||
if (filtered_options.length() == 0) {
|
||||
speak_with_history(tr("system.storage.menu.no_options"), true);
|
||||
} else {
|
||||
speak_storage_menu_prompt(filtered_options[selection]);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
wait(5);
|
||||
@@ -314,7 +332,7 @@ void run_storage_menu() {
|
||||
return;
|
||||
}
|
||||
if (key_pressed(KEY_ESCAPE)) {
|
||||
speak_with_history("Closed.", true);
|
||||
speak_with_history(tr("system.menu.closed"), true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -323,9 +341,9 @@ void run_storage_menu() {
|
||||
if (filter_changed) {
|
||||
if (filtered_options.length() == 0) {
|
||||
if (filter_text.length() > 0) {
|
||||
speak_with_history("No matches for " + filter_text + ".", true);
|
||||
speak_storage_menu_no_matches(filter_text);
|
||||
} else {
|
||||
speak_with_history("No options.", true);
|
||||
speak_with_history(tr("system.menu.no_options"), true);
|
||||
}
|
||||
} else {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
@@ -363,7 +381,7 @@ void run_storage_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
} else if (filter_text.length() > 0) {
|
||||
speak_with_history("No matches for " + filter_text + ".", true);
|
||||
speak_storage_menu_no_matches(filter_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,7 +397,7 @@ void run_storage_menu() {
|
||||
if (filtered_options.length() > 0) {
|
||||
speak_with_history(filtered_options[selection], true);
|
||||
} else if (filter_text.length() > 0) {
|
||||
speak_with_history("No matches for " + filter_text + ".", true);
|
||||
speak_storage_menu_no_matches(filter_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-3
@@ -228,10 +228,19 @@ int get_pet_listener_pos() {
|
||||
}
|
||||
|
||||
string get_health_report() {
|
||||
string report = player_health + " health of " + max_health;
|
||||
dictionary playerArgs;
|
||||
playerArgs.set("health", player_health);
|
||||
playerArgs.set("max", max_health);
|
||||
string report = trf("system.character.report.player", playerArgs);
|
||||
|
||||
if (petActive) {
|
||||
report += ", " + get_pet_display_name() + ", " + petHealth + " health of " + PET_HEALTH_MAX;
|
||||
report += ", loyalty " + petLoyalty + " of " + PET_LOYALTY_MAX;
|
||||
dictionary petArgs;
|
||||
petArgs.set("pet", get_pet_display_name());
|
||||
petArgs.set("health", petHealth);
|
||||
petArgs.set("max", PET_HEALTH_MAX);
|
||||
petArgs.set("loyalty", petLoyalty);
|
||||
petArgs.set("max_loyalty", PET_LOYALTY_MAX);
|
||||
report += ", " + trf("system.character.report.pet", petArgs);
|
||||
}
|
||||
return report;
|
||||
}
|
||||
@@ -891,6 +900,7 @@ bool run_pet_offer_menu(const string& in soundPath, const string& in reasonText)
|
||||
string[] options;
|
||||
options.insert_last("Yes");
|
||||
options.insert_last("No");
|
||||
i18n_translate_string_array_in_place(options);
|
||||
int selection = 0;
|
||||
|
||||
speak_with_history(prompt + " " + options[selection], true);
|
||||
|
||||
@@ -175,7 +175,7 @@ void apply_quest_reward(int score) {
|
||||
}
|
||||
|
||||
message += "\nScore: " + score;
|
||||
text_reader(message, "Quest Rewards", true);
|
||||
text_reader(message, i18n_text("Quest Rewards"), true);
|
||||
attempt_pet_offer_from_quest(score);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,13 +9,14 @@ int run_bat_invasion() {
|
||||
instructions.insert_last("Bats are invading! Throw your spear to defend.");
|
||||
instructions.insert_last("");
|
||||
instructions.insert_last("How to play:");
|
||||
instructions.insert_last(" - Listen for bats flying past from left or right");
|
||||
instructions.insert_last(" - Press SPACE to throw your spear when the bat sounds centered");
|
||||
instructions.insert_last(" - Accurate throws earn 2 points each");
|
||||
instructions.insert_last(" - You have 10 attempts");
|
||||
instructions.insert_last("- Listen for bats flying past from left or right");
|
||||
instructions.insert_last("- Press SPACE to throw your spear when the bat sounds centered");
|
||||
instructions.insert_last("- Accurate throws earn 2 points each");
|
||||
instructions.insert_last("- You have 10 attempts");
|
||||
instructions.insert_last("");
|
||||
instructions.insert_last("Close this screen to begin.");
|
||||
text_reader_lines(instructions, "Quest Instructions", true);
|
||||
i18n_translate_string_array_in_place(instructions);
|
||||
text_reader_lines(instructions, i18n_text("Quest Instructions"), true);
|
||||
|
||||
speak_with_history("Starting.", true);
|
||||
wait(500);
|
||||
|
||||
@@ -6,13 +6,14 @@ int run_catch_the_boomerang() {
|
||||
instructions.insert_last("Throw a boomerang and catch it on the return.");
|
||||
instructions.insert_last("");
|
||||
instructions.insert_last("How to play:");
|
||||
instructions.insert_last(" - Press Space to throw");
|
||||
instructions.insert_last(" - Press Space again when it sounds close");
|
||||
instructions.insert_last(" - There are 5 turns");
|
||||
instructions.insert_last(" - Better timing earns more points (up to 4)");
|
||||
instructions.insert_last("- Press Space to throw");
|
||||
instructions.insert_last("- Press Space again when it sounds close");
|
||||
instructions.insert_last("- There are 5 turns");
|
||||
instructions.insert_last("- Better timing earns more points (up to 4)");
|
||||
instructions.insert_last("");
|
||||
instructions.insert_last("Close this screen to begin.");
|
||||
text_reader_lines(instructions, "Quest Instructions", true);
|
||||
i18n_translate_string_array_in_place(instructions);
|
||||
text_reader_lines(instructions, i18n_text("Quest Instructions"), true);
|
||||
|
||||
wait(500);
|
||||
|
||||
|
||||
@@ -28,14 +28,15 @@ void run_practice_mode() {
|
||||
instructions.insert_last("Repeat the magical pattern to earn favor from the gods.");
|
||||
instructions.insert_last("");
|
||||
instructions.insert_last("Controls:");
|
||||
instructions.insert_last(" F or K - First note (lowest pitch)");
|
||||
instructions.insert_last(" D or J - Second note");
|
||||
instructions.insert_last(" R or I - Third note");
|
||||
instructions.insert_last(" E or U - Fourth note (highest pitch)");
|
||||
instructions.insert_last("F or K - First note (lowest pitch)");
|
||||
instructions.insert_last("D or J - Second note");
|
||||
instructions.insert_last("R or I - Third note");
|
||||
instructions.insert_last("E or U - Fourth note (highest pitch)");
|
||||
instructions.insert_last("");
|
||||
instructions.insert_last("After closing this screen, you can practice the notes.");
|
||||
instructions.insert_last("Press Enter when ready to begin, or Escape to cancel.");
|
||||
text_reader_lines(instructions, "Quest Instructions", true);
|
||||
i18n_translate_string_array_in_place(instructions);
|
||||
text_reader_lines(instructions, i18n_text("Quest Instructions"), true);
|
||||
|
||||
// Practice mode announcement
|
||||
speak_with_history("Practice mode. Press Enter to begin, Escape to cancel.", true);
|
||||
|
||||
@@ -8,14 +8,15 @@ int run_escape_from_hel() {
|
||||
instructions.insert_last("You have plundered the treasure, and the Draugr are displeased.!");
|
||||
instructions.insert_last("");
|
||||
instructions.insert_last("How to play:");
|
||||
instructions.insert_last(" - You run automatically, speed increases over time");
|
||||
instructions.insert_last(" - Listen for open graves approaching (growing louder)");
|
||||
instructions.insert_last(" - Press SPACE to jump over graves");
|
||||
instructions.insert_last(" - Each successful jump earns 2 points");
|
||||
instructions.insert_last(" - The run ends when you fall into a grave");
|
||||
instructions.insert_last("- You run automatically, speed increases over time");
|
||||
instructions.insert_last("- Listen for open graves approaching (growing louder)");
|
||||
instructions.insert_last("- Press SPACE to jump over graves");
|
||||
instructions.insert_last("- Each successful jump earns 2 points");
|
||||
instructions.insert_last("- The run ends when you fall into a grave");
|
||||
instructions.insert_last("");
|
||||
instructions.insert_last("Close this screen to begin.");
|
||||
text_reader_lines(instructions, "Quest Instructions", true);
|
||||
i18n_translate_string_array_in_place(instructions);
|
||||
text_reader_lines(instructions, i18n_text("Quest Instructions"), true);
|
||||
|
||||
wait(500);
|
||||
|
||||
|
||||
@@ -45,13 +45,14 @@ int run_skeletal_bard() {
|
||||
instructions.insert_last("Listen to the melody and count the notes.");
|
||||
instructions.insert_last("");
|
||||
instructions.insert_last("How to play:");
|
||||
instructions.insert_last(" - After the tune, choose the number of notes");
|
||||
instructions.insert_last(" - Use Up/Down to change the number");
|
||||
instructions.insert_last(" - Press Enter to confirm");
|
||||
instructions.insert_last(" - There are 5 rounds, up to 4 points each");
|
||||
instructions.insert_last("- After the tune, choose the number of notes");
|
||||
instructions.insert_last("- Use Up/Down to change the number");
|
||||
instructions.insert_last("- Press Enter to confirm");
|
||||
instructions.insert_last("- There are 5 rounds, up to 4 points each");
|
||||
instructions.insert_last("");
|
||||
instructions.insert_last("Close this screen to begin.");
|
||||
text_reader_lines(instructions, "Quest Instructions", true);
|
||||
i18n_translate_string_array_in_place(instructions);
|
||||
text_reader_lines(instructions, i18n_text("Quest Instructions"), true);
|
||||
|
||||
wait(500);
|
||||
|
||||
|
||||
+46
-206
@@ -1,4 +1,8 @@
|
||||
// Save system
|
||||
#include "libstorm-nvgt/crash_logger.nvgt"
|
||||
#include "libstorm-nvgt/dict_utils.nvgt"
|
||||
#include "libstorm-nvgt/name_sanitize.nvgt"
|
||||
#include "libstorm-nvgt/save_utils.nvgt"
|
||||
|
||||
const string SAVE_EXTENSION = ".dat";
|
||||
const string SAVE_ENCRYPTION_KEY = "draugnorak_save_v1";
|
||||
@@ -145,7 +149,7 @@ string[] get_save_files() {
|
||||
}
|
||||
|
||||
bool sort_string_case_insensitive(const string& in a, const string& in b) {
|
||||
return a.lower() < b.lower();
|
||||
return save_utils_sort_string_case_insensitive(a, b);
|
||||
}
|
||||
|
||||
bool has_save_game() {
|
||||
@@ -153,244 +157,67 @@ bool has_save_game() {
|
||||
}
|
||||
|
||||
string encrypt_save_data(const string& in rawData) {
|
||||
return string_aes_encrypt(rawData, SAVE_ENCRYPTION_KEY);
|
||||
return encrypt_string_aes(rawData, SAVE_ENCRYPTION_KEY);
|
||||
}
|
||||
|
||||
string decrypt_save_data(const string& in encryptedData) {
|
||||
return string_aes_decrypt(encryptedData, SAVE_ENCRYPTION_KEY);
|
||||
return decrypt_string_aes(encryptedData, SAVE_ENCRYPTION_KEY);
|
||||
}
|
||||
|
||||
bool save_data(const string& in filename, const string& in data) {
|
||||
if (data.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
string resolvedPath = resolve_save_path(filename);
|
||||
file tmp;
|
||||
if (!tmp.open(resolvedPath, "wb")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tmp.write(data) < data.length()) {
|
||||
tmp.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
tmp.close();
|
||||
return true;
|
||||
return save_string_file(resolve_save_path(filename), data);
|
||||
}
|
||||
|
||||
bool read_file_string(const string& in filename, string& out data) {
|
||||
string resolvedPath = resolve_save_path(filename);
|
||||
file tmp;
|
||||
if (!tmp.open(resolvedPath, "rb")) {
|
||||
return false;
|
||||
}
|
||||
data = tmp.read();
|
||||
tmp.close();
|
||||
return data.length() > 0;
|
||||
return read_string_file(resolve_save_path(filename), data, false);
|
||||
}
|
||||
|
||||
double get_number(dictionary @data, const string& in key, double defaultValue) {
|
||||
double value;
|
||||
if (@data == null)
|
||||
return defaultValue;
|
||||
if (data.get(key, value))
|
||||
return value;
|
||||
int value_int;
|
||||
if (data.get(key, value_int))
|
||||
return value_int;
|
||||
string value_str;
|
||||
if (data.get(key, value_str)) {
|
||||
return parse_int(value_str);
|
||||
}
|
||||
return defaultValue;
|
||||
return dict_get_number(data, key, defaultValue);
|
||||
}
|
||||
|
||||
bool get_bool(dictionary @data, const string& in key, bool defaultValue) {
|
||||
bool value;
|
||||
if (@data == null)
|
||||
return defaultValue;
|
||||
if (data.get(key, value))
|
||||
return value;
|
||||
int value_int;
|
||||
if (data.get(key, value_int))
|
||||
return value_int != 0;
|
||||
string value_str;
|
||||
if (data.get(key, value_str))
|
||||
return value_str == "1" || value_str == "true";
|
||||
return defaultValue;
|
||||
return dict_get_bool(data, key, defaultValue);
|
||||
}
|
||||
|
||||
bool dictionary_has_keys(dictionary @data) {
|
||||
if (@data == null)
|
||||
return false;
|
||||
string[] @keys = data.get_keys();
|
||||
return keys.length() > 0;
|
||||
return dict_has_keys(data);
|
||||
}
|
||||
|
||||
bool has_number_key(dictionary @data, const string& in key) {
|
||||
double value;
|
||||
if (@data == null)
|
||||
return false;
|
||||
if (data.get(key, value))
|
||||
return true;
|
||||
int value_int;
|
||||
if (data.get(key, value_int))
|
||||
return true;
|
||||
string value_str;
|
||||
if (data.get(key, value_str))
|
||||
return value_str.length() > 0;
|
||||
return false;
|
||||
return dict_has_number_key(data, key);
|
||||
}
|
||||
|
||||
string[] get_string_list(dictionary @data, const string& in key) {
|
||||
string[] result;
|
||||
if (@data == null)
|
||||
return result;
|
||||
if (!data.get(key, result))
|
||||
return result;
|
||||
return result;
|
||||
return dict_get_string_list(data, key);
|
||||
}
|
||||
|
||||
string flatten_exception_text(const string& in text) {
|
||||
string result = "";
|
||||
bool lastWasSpace = false;
|
||||
for (uint i = 0; i < text.length(); i++) {
|
||||
string ch = text.substr(i, 1);
|
||||
if (ch == "\r" || ch == "\n") {
|
||||
if (!lastWasSpace) {
|
||||
result += " | ";
|
||||
lastWasSpace = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
result += ch;
|
||||
lastWasSpace = false;
|
||||
}
|
||||
return result;
|
||||
return log_flatten_multiline(text);
|
||||
}
|
||||
|
||||
string format_log_timestamp() {
|
||||
datetime dt;
|
||||
string stamp = dt.format(DATE_TIME_FORMAT_RFC1123);
|
||||
return "[" + stamp + "]";
|
||||
return log_format_timestamp();
|
||||
}
|
||||
|
||||
void log_unhandled_exception(const string& in context) {
|
||||
string info = get_exception_info();
|
||||
string filePath = get_exception_file();
|
||||
int line = get_exception_line();
|
||||
string func = get_exception_function();
|
||||
string stack = flatten_exception_text(last_exception_call_stack);
|
||||
|
||||
string message = "Unhandled exception";
|
||||
if (context != "")
|
||||
message += " (" + context + ")";
|
||||
if (info != "")
|
||||
message += ": " + info;
|
||||
if (filePath != "")
|
||||
message += " at " + filePath;
|
||||
if (line > 0)
|
||||
message += ":" + line;
|
||||
if (func != "")
|
||||
message += " in " + func;
|
||||
if (stack != "")
|
||||
message += " | stack: " + stack;
|
||||
message += " " + format_log_timestamp();
|
||||
|
||||
file logFile;
|
||||
if (logFile.open(get_crash_log_path(), "ab")) {
|
||||
logFile.write(message + "\r\n");
|
||||
logFile.close();
|
||||
}
|
||||
log_unhandled_exception_to_file(get_crash_log_path(), context);
|
||||
}
|
||||
|
||||
string normalize_player_name(string name) {
|
||||
string result = "";
|
||||
bool lastWasSpace = true;
|
||||
for (uint i = 0; i < name.length(); i++) {
|
||||
string ch = name.substr(i, 1);
|
||||
bool isSpace = (ch == " " || ch == "\t" || ch == "\r" || ch == "\n");
|
||||
if (isSpace) {
|
||||
if (!lastWasSpace) {
|
||||
result += " ";
|
||||
lastWasSpace = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
result += ch;
|
||||
lastWasSpace = false;
|
||||
}
|
||||
if (result.length() > 0 && result.substr(result.length() - 1) == " ") {
|
||||
result = result.substr(0, result.length() - 1);
|
||||
}
|
||||
return result;
|
||||
return normalize_name_whitespace(name);
|
||||
}
|
||||
|
||||
bool is_windows_reserved_name(const string& in upperName) {
|
||||
if (upperName == "CON" || upperName == "PRN" || upperName == "AUX" || upperName == "NUL")
|
||||
return true;
|
||||
if (upperName.length() == 4 && upperName.substr(0, 3) == "COM") {
|
||||
int num = parse_int(upperName.substr(3));
|
||||
if (num >= 1 && num <= 9)
|
||||
return true;
|
||||
}
|
||||
if (upperName.length() == 4 && upperName.substr(0, 3) == "LPT") {
|
||||
int num = parse_int(upperName.substr(3));
|
||||
if (num >= 1 && num <= 9)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return is_windows_reserved_filename(upperName);
|
||||
}
|
||||
|
||||
string sanitize_save_filename_base(string name) {
|
||||
string normalized = normalize_player_name(name);
|
||||
string result = "";
|
||||
bool lastSeparator = false;
|
||||
|
||||
for (uint i = 0; i < normalized.length(); i++) {
|
||||
string ch = normalized.substr(i, 1);
|
||||
bool isUpper = (ch >= "A" && ch <= "Z");
|
||||
bool isLower = (ch >= "a" && ch <= "z");
|
||||
bool isDigit = (ch >= "0" && ch <= "9");
|
||||
if (isUpper || isLower || isDigit) {
|
||||
result += ch;
|
||||
lastSeparator = false;
|
||||
continue;
|
||||
}
|
||||
if (ch == " " || ch == "_" || ch == "-") {
|
||||
if (!lastSeparator && result.length() > 0) {
|
||||
result += "_";
|
||||
lastSeparator = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (result.length() > 0 && result.substr(result.length() - 1) == "_") {
|
||||
result = result.substr(0, result.length() - 1);
|
||||
}
|
||||
if (result.length() == 0) {
|
||||
result = "character";
|
||||
}
|
||||
if (result.length() > 40) {
|
||||
result = result.substr(0, 40);
|
||||
}
|
||||
while (result.length() > 0 && result.substr(result.length() - 1) == "_") {
|
||||
result = result.substr(0, result.length() - 1);
|
||||
}
|
||||
string upperName = result.upper();
|
||||
if (upperName == "." || upperName == "..") {
|
||||
result = "character";
|
||||
upperName = result.upper();
|
||||
}
|
||||
if (is_windows_reserved_name(upperName)) {
|
||||
result = "save_" + result;
|
||||
}
|
||||
return result;
|
||||
return sanitize_filename_base_with_reserved_prefix(name, 40, "character", "save_");
|
||||
}
|
||||
|
||||
string get_save_filename_for_name(const string& in name) {
|
||||
return sanitize_save_filename_base(name) + SAVE_EXTENSION;
|
||||
return build_filename_from_name_ex(name, SAVE_EXTENSION, 40, "character", "save_");
|
||||
}
|
||||
|
||||
string strip_save_extension(const string& in filename) {
|
||||
@@ -504,10 +331,16 @@ string pick_random_name_for_sex(int sex, const string[] @usedNames) {
|
||||
return pick_random_name(male_name_pool, usedNames);
|
||||
}
|
||||
|
||||
string get_localized_sex_label(int sexValue) {
|
||||
if (sexValue == SEX_FEMALE)
|
||||
return tr("system.sex.female");
|
||||
return tr("system.sex.male");
|
||||
}
|
||||
|
||||
bool select_player_sex(int& out sex) {
|
||||
string[] options = {"Male", "Female"};
|
||||
string[] options = {get_localized_sex_label(SEX_MALE), get_localized_sex_label(SEX_FEMALE)};
|
||||
int selection = 0;
|
||||
string prompt = "Choose your sex.";
|
||||
string prompt = tr("system.new_character.choose_sex");
|
||||
speak_with_history(prompt + " " + options[selection], true);
|
||||
|
||||
while (true) {
|
||||
@@ -548,14 +381,16 @@ bool setup_new_character() {
|
||||
|
||||
string[] existingNames = get_existing_character_names();
|
||||
while (true) {
|
||||
string entered = ui_input_box("Draugnorak", "Enter your name or press Enter for random.", "");
|
||||
string entered = ui_input_box(tr("system.ui.window_title"), tr("system.new_character.enter_name"), "");
|
||||
string normalized = normalize_player_name(entered);
|
||||
if (normalized.length() == 0) {
|
||||
normalized = pick_random_name_for_sex(selectedSex, existingNames);
|
||||
}
|
||||
string saveFile = get_save_filename_for_name(normalized);
|
||||
if (file_exists(resolve_save_path(saveFile))) {
|
||||
int confirm = ui_question("", "Save found for " + normalized + ". Overwrite?");
|
||||
dictionary overwriteArgs;
|
||||
overwriteArgs.set("name", normalized);
|
||||
int confirm = ui_question("", trf("system.new_character.save_exists_overwrite", overwriteArgs));
|
||||
if (confirm != 1) {
|
||||
continue;
|
||||
}
|
||||
@@ -588,8 +423,11 @@ bool select_save_file(string& out filename) {
|
||||
displayName = strip_save_extension(files[i]);
|
||||
options.insert_last(displayName);
|
||||
} else {
|
||||
string sex_label = (sex == SEX_FEMALE) ? "female" : "male";
|
||||
options.insert_last(displayName + ", " + sex_label + ", day " + day);
|
||||
dictionary optionArgs;
|
||||
optionArgs.set("name", displayName);
|
||||
optionArgs.set("sex", get_localized_sex_label(sex));
|
||||
optionArgs.set("day", day);
|
||||
options.insert_last(trf("system.load_game.option_with_metadata", optionArgs));
|
||||
}
|
||||
displayNames.insert_last(displayName);
|
||||
sexValues.insert_last(sex);
|
||||
@@ -624,12 +462,13 @@ bool select_save_file(string& out filename) {
|
||||
return true;
|
||||
}
|
||||
if (key_pressed(KEY_DELETE)) {
|
||||
string prompt = "Are you sure you want to delete the character " + displayNames[selection];
|
||||
dictionary deleteArgs;
|
||||
deleteArgs.set("name", displayNames[selection]);
|
||||
string prompt = trf("system.load_game.delete_confirm_base", deleteArgs);
|
||||
if (hasMetadata[selection]) {
|
||||
string sex_label = (sexValues[selection] == SEX_FEMALE) ? "female" : "male";
|
||||
prompt += " gender " + sex_label + " days " + dayValues[selection] + "?";
|
||||
} else {
|
||||
prompt += "?";
|
||||
deleteArgs.set("sex", get_localized_sex_label(sexValues[selection]));
|
||||
deleteArgs.set("day", dayValues[selection]);
|
||||
prompt = trf("system.load_game.delete_confirm_with_metadata", deleteArgs);
|
||||
}
|
||||
int confirm = ui_question("", prompt);
|
||||
if (confirm == 1) {
|
||||
@@ -638,7 +477,8 @@ bool select_save_file(string& out filename) {
|
||||
refreshList = true;
|
||||
break;
|
||||
} else {
|
||||
ui_info_box("Draugnorak", "Delete Save", "Unable to delete save.");
|
||||
ui_info_box(tr("system.ui.window_title"), tr("system.load_game.delete_save_heading"),
|
||||
tr("system.load_game.delete_save_failed"));
|
||||
speak_with_history(options[selection], true);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Compatibility aliases that keep legacy text_reader* callsites unchanged.
|
||||
// file_viewer* is provided by libstorm-nvgt/docs_browser.nvgt.
|
||||
string text_reader(string content, string title = "Text Reader", bool readOnly = true) {
|
||||
return file_viewer(content, title, readOnly);
|
||||
return file_viewer(content, i18n_text(title), readOnly);
|
||||
}
|
||||
|
||||
string text_reader_lines(string[] lines, string title = "Text Reader", bool readOnly = true) {
|
||||
return file_viewer_lines(lines, title, readOnly);
|
||||
return file_viewer_lines(lines, i18n_text(title), readOnly);
|
||||
}
|
||||
|
||||
string text_reader_file(string filePath, string title = "", bool readOnly = true) {
|
||||
return file_viewer_file(filePath, title, readOnly);
|
||||
return file_viewer_file(filePath, i18n_text(title), readOnly);
|
||||
}
|
||||
|
||||
@@ -91,12 +91,14 @@ void clear_world_drops() {
|
||||
|
||||
bool try_pickup_small_game(string game_type) {
|
||||
if (get_personal_count(ITEM_SMALL_GAME) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more small game.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_SMALL_GAME);
|
||||
return false;
|
||||
}
|
||||
add_personal_count(ITEM_SMALL_GAME, 1);
|
||||
personal_small_game_types.insert_last(game_type);
|
||||
speak_with_history("Picked up " + game_type + ".", true);
|
||||
dictionary args;
|
||||
args.set("item", i18n_translate_speech_message(game_type));
|
||||
speak_with_history(trf("system.pickup.item", args), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -107,26 +109,32 @@ bool try_pickup_world_drop(WorldDrop @drop) {
|
||||
if (drop.type == "arrow") {
|
||||
int max_arrows = get_arrow_limit();
|
||||
if (max_arrows <= 0) {
|
||||
speak_with_history("You need a quiver to carry arrows.", true);
|
||||
speak_need_quiver_for_arrows();
|
||||
return false;
|
||||
}
|
||||
if (get_personal_count(ITEM_ARROWS) >= max_arrows) {
|
||||
speak_with_history("You can't carry any more arrows.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_ARROWS);
|
||||
return false;
|
||||
}
|
||||
add_personal_count(ITEM_ARROWS, 1);
|
||||
speak_with_history("Picked up arrow.", true);
|
||||
dictionary args;
|
||||
args.set("item", get_item_label_singular(ITEM_ARROWS));
|
||||
speak_with_history(trf("system.pickup.item", args), true);
|
||||
return true;
|
||||
}
|
||||
if (drop.type == "boar carcass") {
|
||||
if (get_personal_count(ITEM_BOAR_CARCASSES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more boar carcasses.", true);
|
||||
speak_cant_carry_any_more_item(ITEM_BOAR_CARCASSES);
|
||||
return false;
|
||||
}
|
||||
add_personal_count(ITEM_BOAR_CARCASSES, 1);
|
||||
speak_with_history("Picked up boar carcass.", true);
|
||||
dictionary args;
|
||||
args.set("item", get_item_label_singular(ITEM_BOAR_CARCASSES));
|
||||
speak_with_history(trf("system.pickup.item", args), true);
|
||||
return true;
|
||||
}
|
||||
speak_with_history("Picked up " + drop.type + ".", true);
|
||||
dictionary args;
|
||||
args.set("item", i18n_translate_speech_message(drop.type));
|
||||
speak_with_history(trf("system.pickup.item", args), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user