|
|
|
|
@@ -183,6 +183,51 @@ class Tree {
|
|
|
|
|
}
|
|
|
|
|
Tree@[] trees;
|
|
|
|
|
|
|
|
|
|
const int SEARCH_POOL_STREAM_BANK = 0;
|
|
|
|
|
const int SEARCH_POOL_FOREST = 1;
|
|
|
|
|
const int SEARCH_POOL_STONE_TERRAIN = 2;
|
|
|
|
|
const int SEARCH_POOL_COUNT = 3;
|
|
|
|
|
|
|
|
|
|
class SearchPool {
|
|
|
|
|
int[] item_types;
|
|
|
|
|
int[] weights;
|
|
|
|
|
string[] found_messages;
|
|
|
|
|
string[] terrain_tags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SearchPool@[] search_pools;
|
|
|
|
|
int[] search_mass_noun_items;
|
|
|
|
|
|
|
|
|
|
void init_search_pools() {
|
|
|
|
|
// Add or adjust all terrain-based search content here.
|
|
|
|
|
// Keep item_types, weights, and found_messages aligned by index.
|
|
|
|
|
// Leave found_messages empty to use the auto "Found a/an X." or "Found X." logic.
|
|
|
|
|
// Use terrain_tags to map pool usage without touching perform_search().
|
|
|
|
|
search_pools.resize(SEARCH_POOL_COUNT);
|
|
|
|
|
|
|
|
|
|
@search_pools[SEARCH_POOL_STREAM_BANK] = SearchPool();
|
|
|
|
|
search_pools[SEARCH_POOL_STREAM_BANK].item_types = { ITEM_REEDS, ITEM_CLAY };
|
|
|
|
|
search_pools[SEARCH_POOL_STREAM_BANK].weights = { 30, 70 };
|
|
|
|
|
search_pools[SEARCH_POOL_STREAM_BANK].found_messages = { "Found a reed.", "Found clay." };
|
|
|
|
|
search_pools[SEARCH_POOL_STREAM_BANK].terrain_tags = { "stream_bank" };
|
|
|
|
|
|
|
|
|
|
@search_pools[SEARCH_POOL_FOREST] = SearchPool();
|
|
|
|
|
search_pools[SEARCH_POOL_FOREST].item_types = { ITEM_STICKS, ITEM_VINES };
|
|
|
|
|
search_pools[SEARCH_POOL_FOREST].weights = { 1, 1 };
|
|
|
|
|
search_pools[SEARCH_POOL_FOREST].found_messages = { "Found a stick.", "Found a vine." };
|
|
|
|
|
search_pools[SEARCH_POOL_FOREST].terrain_tags = { "forest", "deep_forest" };
|
|
|
|
|
|
|
|
|
|
@search_pools[SEARCH_POOL_STONE_TERRAIN] = SearchPool();
|
|
|
|
|
search_pools[SEARCH_POOL_STONE_TERRAIN].item_types = { ITEM_STONES };
|
|
|
|
|
search_pools[SEARCH_POOL_STONE_TERRAIN].weights = { 1 };
|
|
|
|
|
search_pools[SEARCH_POOL_STONE_TERRAIN].found_messages = { "Found a stone." };
|
|
|
|
|
search_pools[SEARCH_POOL_STONE_TERRAIN].terrain_tags = { "gravel", "stone", "hard_stone" };
|
|
|
|
|
|
|
|
|
|
// Mass nouns for auto "Found X." fallback (no article).
|
|
|
|
|
// Add new mass nouns here when adding search items that should not use "a/an".
|
|
|
|
|
search_mass_noun_items = { ITEM_CLAY };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string get_tree_area_terrain(int areaStart, int areaEnd) {
|
|
|
|
|
if (areaStart >= BASE_END + 1 && areaEnd <= GRASS_END) {
|
|
|
|
|
return "grass";
|
|
|
|
|
@@ -505,6 +550,121 @@ 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;
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
list_text = item_name;
|
|
|
|
|
} else if (i == item_types.length() - 1) {
|
|
|
|
|
if (item_types.length() == 2) {
|
|
|
|
|
list_text += " or " + item_name;
|
|
|
|
|
} else {
|
|
|
|
|
list_text += ", or " + item_name;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
list_text += ", " + item_name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return list_text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool is_mass_noun_item(int item_type) {
|
|
|
|
|
for (uint i = 0; i < search_mass_noun_items.length(); i++) {
|
|
|
|
|
if (search_mass_noun_items[i] == item_type) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 + ".";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int get_search_weight(int[] weights, uint index) {
|
|
|
|
|
if (index >= weights.length()) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
int weight = weights[index];
|
|
|
|
|
if (weight <= 0) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return weight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool try_find_weighted_resource(int[] item_types, int[] weights, string[] found_messages) {
|
|
|
|
|
if (item_types.length() == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int total_weight = 0;
|
|
|
|
|
int[] available_indices;
|
|
|
|
|
available_indices.resize(0);
|
|
|
|
|
|
|
|
|
|
for (uint i = 0; i < item_types.length(); i++) {
|
|
|
|
|
if (get_personal_count(item_types[i]) >= get_personal_stack_limit()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
int weight = get_search_weight(weights, i);
|
|
|
|
|
total_weight += weight;
|
|
|
|
|
available_indices.insert_last(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (available_indices.length() == 0) {
|
|
|
|
|
speak_with_history("You can't carry any more " + build_item_list(item_types) + ".", true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int roll = random(1, total_weight);
|
|
|
|
|
int running_weight = 0;
|
|
|
|
|
uint chosen_index = available_indices[0];
|
|
|
|
|
for (uint i = 0; i < available_indices.length(); i++) {
|
|
|
|
|
uint candidate_index = available_indices[i];
|
|
|
|
|
int weight = get_search_weight(weights, candidate_index);
|
|
|
|
|
running_weight += weight;
|
|
|
|
|
if (roll <= running_weight) {
|
|
|
|
|
chosen_index = candidate_index;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int item_type = item_types[chosen_index];
|
|
|
|
|
add_personal_count(item_type, 1);
|
|
|
|
|
play_item_collect_sound(item_registry[item_type].singular);
|
|
|
|
|
|
|
|
|
|
if (found_messages.length() > chosen_index && found_messages[chosen_index] != "") {
|
|
|
|
|
speak_with_history(found_messages[chosen_index], true);
|
|
|
|
|
} else {
|
|
|
|
|
speak_with_history(get_auto_found_message(item_type), true);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool try_search_for_terrain(string terrain_type) {
|
|
|
|
|
for (uint i = 0; i < search_pools.length(); i++) {
|
|
|
|
|
if (search_pools[i] is null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
for (uint j = 0; j < search_pools[i].terrain_tags.length(); j++) {
|
|
|
|
|
if (search_pools[i].terrain_tags[j] == terrain_type) {
|
|
|
|
|
return try_find_weighted_resource(search_pools[i].item_types,
|
|
|
|
|
search_pools[i].weights, search_pools[i].found_messages);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void perform_search(int current_x)
|
|
|
|
|
{
|
|
|
|
|
// First priority: Check for world drops on this tile or adjacent
|
|
|
|
|
@@ -579,36 +739,7 @@ void perform_search(int current_x)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (near_stream_bank) {
|
|
|
|
|
bool found_reed = random(1, 100) <= 30;
|
|
|
|
|
if (found_reed) {
|
|
|
|
|
if (get_personal_count(ITEM_REEDS) < get_personal_stack_limit()) {
|
|
|
|
|
add_personal_count(ITEM_REEDS, 1);
|
|
|
|
|
play_item_collect_sound("reed");
|
|
|
|
|
speak_with_history("Found a reed.", true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (get_personal_count(ITEM_CLAY) < get_personal_stack_limit()) {
|
|
|
|
|
add_personal_count(ITEM_CLAY, 1);
|
|
|
|
|
play_item_collect_sound("clay");
|
|
|
|
|
speak_with_history("Found clay.", true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found_reed && get_personal_count(ITEM_REEDS) < get_personal_stack_limit()) {
|
|
|
|
|
add_personal_count(ITEM_REEDS, 1);
|
|
|
|
|
play_item_collect_sound("reed");
|
|
|
|
|
speak_with_history("Found a reed.", true);
|
|
|
|
|
} else if (found_reed && get_personal_count(ITEM_CLAY) < get_personal_stack_limit()) {
|
|
|
|
|
add_personal_count(ITEM_CLAY, 1);
|
|
|
|
|
play_item_collect_sound("clay");
|
|
|
|
|
speak_with_history("Found clay.", true);
|
|
|
|
|
} else if (found_reed) {
|
|
|
|
|
speak_with_history("You can't carry any more reeds.", true);
|
|
|
|
|
} else {
|
|
|
|
|
speak_with_history("You can't carry any more clay.", true);
|
|
|
|
|
}
|
|
|
|
|
try_search_for_terrain("stream_bank");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -706,101 +837,7 @@ void perform_search(int current_x)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Stone terrain - check for stones
|
|
|
|
|
bool is_stone_terrain = false;
|
|
|
|
|
|
|
|
|
|
// Check base gravel area (20-34)
|
|
|
|
|
if (current_x >= GRAVEL_START && current_x <= GRAVEL_END) {
|
|
|
|
|
is_stone_terrain = true;
|
|
|
|
|
}
|
|
|
|
|
// Check expanded areas
|
|
|
|
|
else if (expanded_area_start != -1 && current_x >= expanded_area_start && current_x <= expanded_area_end) {
|
|
|
|
|
// Check for mountain terrain first
|
|
|
|
|
MountainRange@ mountain = get_mountain_at(current_x);
|
|
|
|
|
if (mountain !is null) {
|
|
|
|
|
string terrain = mountain.get_terrain_at(current_x);
|
|
|
|
|
if (terrain == "stone" || terrain == "hard_stone" || terrain == "gravel") {
|
|
|
|
|
is_stone_terrain = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Regular expanded area - check terrain type
|
|
|
|
|
int index = current_x - expanded_area_start;
|
|
|
|
|
if (index >= 0 && index < int(expanded_terrain_types.length())) {
|
|
|
|
|
string terrain = expanded_terrain_types[index];
|
|
|
|
|
// Handle "mountain:terrain" format from older saves
|
|
|
|
|
if (terrain.find("mountain:") == 0) {
|
|
|
|
|
terrain = terrain.substr(9);
|
|
|
|
|
}
|
|
|
|
|
if (terrain == "stone" || terrain == "hard_stone" || terrain == "gravel") {
|
|
|
|
|
is_stone_terrain = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_stone_terrain)
|
|
|
|
|
{
|
|
|
|
|
if (get_personal_count(ITEM_STONES) < get_personal_stack_limit())
|
|
|
|
|
{
|
|
|
|
|
add_personal_count(ITEM_STONES, 1);
|
|
|
|
|
play_item_collect_sound("stone");
|
|
|
|
|
speak_with_history("Found a stone.", true);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
speak_with_history("You can't carry any more stones.", true);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Forest terrain - check for sticks and vines
|
|
|
|
|
bool is_forest_terrain = false;
|
|
|
|
|
string current_terrain = "";
|
|
|
|
|
|
|
|
|
|
// Check expanded areas for forest/deep_forest
|
|
|
|
|
if (expanded_area_start != -1 && current_x >= expanded_area_start && current_x <= expanded_area_end) {
|
|
|
|
|
// Check for mountain terrain first
|
|
|
|
|
MountainRange@ mountain = get_mountain_at(current_x);
|
|
|
|
|
if (mountain !is null) {
|
|
|
|
|
current_terrain = mountain.get_terrain_at(current_x);
|
|
|
|
|
} else {
|
|
|
|
|
// Regular expanded area - check terrain type
|
|
|
|
|
int index = current_x - expanded_area_start;
|
|
|
|
|
if (index >= 0 && index < int(expanded_terrain_types.length())) {
|
|
|
|
|
current_terrain = expanded_terrain_types[index];
|
|
|
|
|
// Handle "mountain:terrain" format from older saves
|
|
|
|
|
if (current_terrain.find("mountain:") == 0) {
|
|
|
|
|
current_terrain = current_terrain.substr(9);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (current_terrain == "forest" || current_terrain == "deep_forest") {
|
|
|
|
|
is_forest_terrain = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_forest_terrain)
|
|
|
|
|
{
|
|
|
|
|
bool can_find_stick = get_personal_count(ITEM_STICKS) < get_personal_stack_limit();
|
|
|
|
|
bool can_find_vine = get_personal_count(ITEM_VINES) < get_personal_stack_limit();
|
|
|
|
|
|
|
|
|
|
if (!can_find_stick && !can_find_vine) {
|
|
|
|
|
speak_with_history("You can't carry any more sticks or vines.", true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Random choice: if both available, 50/50. If only one, find that.
|
|
|
|
|
bool find_stick = can_find_stick && (!can_find_vine || random(0, 1) == 0);
|
|
|
|
|
|
|
|
|
|
if (find_stick) {
|
|
|
|
|
add_personal_count(ITEM_STICKS, 1);
|
|
|
|
|
play_item_collect_sound("stick");
|
|
|
|
|
speak_with_history("Found a stick.", true);
|
|
|
|
|
} else {
|
|
|
|
|
add_personal_count(ITEM_VINES, 1);
|
|
|
|
|
play_item_collect_sound("vine");
|
|
|
|
|
speak_with_history("Found a vine.", true);
|
|
|
|
|
}
|
|
|
|
|
if (try_search_for_terrain(search_terrain)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|