A few bug fixes, new item, canoe, added.
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
string get_footstep_sound(int current_x, int base_end, int grass_end)
|
||||
{
|
||||
// Check if in water first (regular streams or mountain streams)
|
||||
if (is_deep_stream_at(current_x)) {
|
||||
return "sounds/terrain/deep_water.ogg";
|
||||
}
|
||||
if (is_position_in_water(current_x) || is_mountain_stream_at(current_x)) {
|
||||
return "sounds/terrain/shallow_water.ogg";
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ const int ARROW_CAPACITY_PER_QUIVER = 12;
|
||||
// Zombie settings
|
||||
const int ZOMBIE_HEALTH = 12;
|
||||
const int ZOMBIE_MAX_COUNT = 5;
|
||||
const int ZOMBIE_MAX_COUNT_CAP = 12;
|
||||
const int ZOMBIE_MOVE_INTERVAL = 1000;
|
||||
const int ZOMBIE_ATTACK_INTERVAL = 1600;
|
||||
const int ZOMBIE_DAMAGE_MIN = 4;
|
||||
@@ -239,4 +240,3 @@ const int RESIDENT_COLLECTION_CHANCE = 10; // 10% chance per basket per hour
|
||||
int abs(int value) {
|
||||
return value < 0 ? -value : value;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ void run_tools_menu() {
|
||||
"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)"
|
||||
};
|
||||
@@ -41,8 +42,9 @@ void run_tools_menu() {
|
||||
else if (selection == 3) craft_fishing_pole();
|
||||
else if (selection == 4) craft_rope();
|
||||
else if (selection == 5) craft_quiver();
|
||||
else if (selection == 6) craft_reed_basket();
|
||||
else if (selection == 7) craft_clay_pot();
|
||||
else if (selection == 6) craft_canoe();
|
||||
else if (selection == 7) craft_reed_basket();
|
||||
else if (selection == 8) craft_clay_pot();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -53,8 +55,9 @@ void run_tools_menu() {
|
||||
else if (selection == 3) craft_fishing_pole_max();
|
||||
else if (selection == 4) craft_rope_max();
|
||||
else if (selection == 5) craft_quiver_max();
|
||||
else if (selection == 6) craft_reed_basket_max();
|
||||
else if (selection == 7) craft_clay_pot_max();
|
||||
else if (selection == 6) craft_canoe_max();
|
||||
else if (selection == 7) craft_reed_basket_max();
|
||||
else if (selection == 8) craft_clay_pot_max();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -296,6 +299,81 @@ void craft_quiver_max() {
|
||||
speak_with_history("Crafted " + maxCraft + " Quivers.", true);
|
||||
}
|
||||
|
||||
void craft_canoe() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_LOGS) < 4) missing += "4 logs ";
|
||||
if (get_personal_count(ITEM_STICKS) < 11) missing += "11 sticks ";
|
||||
if (get_personal_count(ITEM_VINES) < 11) missing += "11 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_ROPES) < 2) missing += "2 rope ";
|
||||
if (get_personal_count(ITEM_REEDS) < 6) missing += "6 reeds ";
|
||||
|
||||
if (missing == "") {
|
||||
if (get_personal_count(ITEM_CANOES) >= get_personal_stack_limit()) {
|
||||
speak_with_history("You can't carry any more canoes.", true);
|
||||
return;
|
||||
}
|
||||
simulate_crafting(40);
|
||||
add_personal_count(ITEM_LOGS, -4);
|
||||
add_personal_count(ITEM_STICKS, -11);
|
||||
add_personal_count(ITEM_VINES, -11);
|
||||
add_personal_count(ITEM_SKINS, -6);
|
||||
add_personal_count(ITEM_ROPES, -2);
|
||||
add_personal_count(ITEM_REEDS, -6);
|
||||
add_personal_count(ITEM_CANOES, 1);
|
||||
speak_with_history("Crafted a Canoe.", true);
|
||||
} else {
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
int maxByLogs = get_personal_count(ITEM_LOGS) / 4;
|
||||
int maxBySticks = get_personal_count(ITEM_STICKS) / 11;
|
||||
int maxByVines = get_personal_count(ITEM_VINES) / 11;
|
||||
int maxBySkins = get_personal_count(ITEM_SKINS) / 6;
|
||||
int maxByRopes = get_personal_count(ITEM_ROPES) / 2;
|
||||
int maxByReeds = get_personal_count(ITEM_REEDS) / 6;
|
||||
int maxCraft = maxByLogs;
|
||||
if (maxBySticks < maxCraft) maxCraft = maxBySticks;
|
||||
if (maxByVines < maxCraft) maxCraft = maxByVines;
|
||||
if (maxBySkins < maxCraft) maxCraft = maxBySkins;
|
||||
if (maxByRopes < maxCraft) maxCraft = maxByRopes;
|
||||
if (maxByReeds < maxCraft) maxCraft = maxByReeds;
|
||||
|
||||
int space = get_personal_stack_limit() - get_personal_count(ITEM_CANOES);
|
||||
if (maxCraft > space) maxCraft = space;
|
||||
|
||||
if (maxCraft <= 0) {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_LOGS) < 4) missing += "4 logs ";
|
||||
if (get_personal_count(ITEM_STICKS) < 11) missing += "11 sticks ";
|
||||
if (get_personal_count(ITEM_VINES) < 11) missing += "11 vines ";
|
||||
if (get_personal_count(ITEM_SKINS) < 6) missing += "6 skins ";
|
||||
if (get_personal_count(ITEM_ROPES) < 2) missing += "2 rope ";
|
||||
if (get_personal_count(ITEM_REEDS) < 6) missing += "6 reeds ";
|
||||
speak_with_history("Missing: " + missing, true);
|
||||
return;
|
||||
}
|
||||
|
||||
int totalCost = maxCraft * 40;
|
||||
int craftTime = (totalCost < maxCraft * 4) ? maxCraft * 4 : totalCost;
|
||||
simulate_crafting(craftTime);
|
||||
add_personal_count(ITEM_LOGS, -(maxCraft * 4));
|
||||
add_personal_count(ITEM_STICKS, -(maxCraft * 11));
|
||||
add_personal_count(ITEM_VINES, -(maxCraft * 11));
|
||||
add_personal_count(ITEM_SKINS, -(maxCraft * 6));
|
||||
add_personal_count(ITEM_ROPES, -(maxCraft * 2));
|
||||
add_personal_count(ITEM_REEDS, -(maxCraft * 6));
|
||||
add_personal_count(ITEM_CANOES, maxCraft);
|
||||
speak_with_history("Crafted " + maxCraft + " Canoes.", true);
|
||||
}
|
||||
|
||||
void craft_reed_basket() {
|
||||
string missing = "";
|
||||
if (get_personal_count(ITEM_REEDS) < 3) missing += "3 reeds ";
|
||||
|
||||
@@ -183,7 +183,14 @@ void update_undeads() {
|
||||
return;
|
||||
}
|
||||
|
||||
while (undeads.length() < ZOMBIE_MAX_COUNT) {
|
||||
int extra = 0;
|
||||
if (MAP_SIZE > 35) {
|
||||
extra = (MAP_SIZE - 35) / 15;
|
||||
}
|
||||
int maxCount = ZOMBIE_MAX_COUNT + extra;
|
||||
if (maxCount > ZOMBIE_MAX_COUNT_CAP) maxCount = ZOMBIE_MAX_COUNT_CAP;
|
||||
|
||||
while (undeads.length() < maxCount) {
|
||||
spawn_undead();
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,8 @@ class Tree {
|
||||
|
||||
int areaStart = 0;
|
||||
int areaEnd = 0;
|
||||
if (!get_tree_area_bounds_for_position(position, areaStart, areaEnd)) {
|
||||
string areaTerrain = "";
|
||||
if (!get_tree_area_bounds_for_position(position, areaStart, areaEnd, areaTerrain)) {
|
||||
areaStart = BASE_END + 1;
|
||||
areaEnd = GRASS_END;
|
||||
}
|
||||
@@ -182,10 +183,38 @@ class Tree {
|
||||
}
|
||||
Tree@[] trees;
|
||||
|
||||
bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out areaEnd) {
|
||||
string get_tree_area_terrain(int areaStart, int areaEnd) {
|
||||
if (areaStart >= BASE_END + 1 && areaEnd <= GRASS_END) {
|
||||
return "grass";
|
||||
}
|
||||
|
||||
if (expanded_area_start != -1 && areaStart >= expanded_area_start && areaEnd <= expanded_area_end) {
|
||||
int index = areaStart - expanded_area_start;
|
||||
if (index >= 0 && index < int(expanded_terrain_types.length())) {
|
||||
string terrain = expanded_terrain_types[index];
|
||||
if (terrain.find("mountain:") == 0) {
|
||||
terrain = terrain.substr(9);
|
||||
}
|
||||
return terrain;
|
||||
}
|
||||
}
|
||||
|
||||
return "grass";
|
||||
}
|
||||
|
||||
int get_tree_max_for_area(int areaStart, int areaEnd) {
|
||||
string terrain = get_tree_area_terrain(areaStart, areaEnd);
|
||||
if (terrain == "forest" || terrain == "deep_forest") {
|
||||
return TREE_MAX_PER_AREA + 1;
|
||||
}
|
||||
return TREE_MAX_PER_AREA;
|
||||
}
|
||||
|
||||
bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out areaEnd, string &out areaTerrain) {
|
||||
if (pos >= BASE_END + 1 && pos <= GRASS_END) {
|
||||
areaStart = BASE_END + 1;
|
||||
areaEnd = GRASS_END;
|
||||
areaTerrain = "grass";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -195,21 +224,36 @@ bool get_tree_area_bounds_for_position(int pos, int &out areaStart, int &out are
|
||||
|
||||
int index = pos - expanded_area_start;
|
||||
if (index < 0 || index >= int(expanded_terrain_types.length())) return false;
|
||||
if (expanded_terrain_types[index] != "grass") return false;
|
||||
string terrain = expanded_terrain_types[index];
|
||||
if (terrain.find("mountain:") == 0) {
|
||||
terrain = terrain.substr(9);
|
||||
}
|
||||
if (terrain != "grass" && terrain != "forest" && terrain != "deep_forest") return false;
|
||||
|
||||
int left = index;
|
||||
while (left > 0 && expanded_terrain_types[left - 1] == "grass") {
|
||||
while (left > 0) {
|
||||
string leftTerrain = expanded_terrain_types[left - 1];
|
||||
if (leftTerrain.find("mountain:") == 0) {
|
||||
leftTerrain = leftTerrain.substr(9);
|
||||
}
|
||||
if (leftTerrain != terrain) break;
|
||||
left--;
|
||||
}
|
||||
|
||||
int right = index;
|
||||
int maxIndex = int(expanded_terrain_types.length()) - 1;
|
||||
while (right < maxIndex && expanded_terrain_types[right + 1] == "grass") {
|
||||
while (right < maxIndex) {
|
||||
string rightTerrain = expanded_terrain_types[right + 1];
|
||||
if (rightTerrain.find("mountain:") == 0) {
|
||||
rightTerrain = rightTerrain.substr(9);
|
||||
}
|
||||
if (rightTerrain != terrain) break;
|
||||
right++;
|
||||
}
|
||||
|
||||
areaStart = expanded_area_start + left;
|
||||
areaEnd = expanded_area_start + right;
|
||||
areaTerrain = terrain;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -242,7 +286,8 @@ bool tree_too_close_in_area(int pos, int areaStart, int areaEnd, Tree@ ignoreTre
|
||||
}
|
||||
|
||||
bool place_tree_in_area(Tree@ tree, int areaStart, int areaEnd) {
|
||||
if (count_trees_in_area(areaStart, areaEnd, tree) >= TREE_MAX_PER_AREA) {
|
||||
int maxTrees = get_tree_max_for_area(areaStart, areaEnd);
|
||||
if (count_trees_in_area(areaStart, areaEnd, tree) >= maxTrees) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -259,7 +304,8 @@ bool place_tree_in_area(Tree@ tree, int areaStart, int areaEnd) {
|
||||
}
|
||||
|
||||
bool spawn_tree_in_area(int areaStart, int areaEnd) {
|
||||
if (count_trees_in_area(areaStart, areaEnd, null) >= TREE_MAX_PER_AREA) {
|
||||
int maxTrees = get_tree_max_for_area(areaStart, areaEnd);
|
||||
if (count_trees_in_area(areaStart, areaEnd, null) >= maxTrees) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -280,7 +326,7 @@ void spawn_trees(int grass_start, int grass_end) {
|
||||
spawn_tree_in_area(grass_start, grass_end);
|
||||
}
|
||||
|
||||
void get_grass_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||
void get_tree_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||
areaStarts.resize(0);
|
||||
areaEnds.resize(0);
|
||||
|
||||
@@ -291,9 +337,18 @@ void get_grass_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||
int total = int(expanded_terrain_types.length());
|
||||
int index = 0;
|
||||
while (index < total) {
|
||||
if (expanded_terrain_types[index] == "grass") {
|
||||
string terrain = expanded_terrain_types[index];
|
||||
if (terrain.find("mountain:") == 0) {
|
||||
terrain = terrain.substr(9);
|
||||
}
|
||||
if (terrain == "grass" || terrain == "forest" || terrain == "deep_forest") {
|
||||
int segmentStart = index;
|
||||
while (index + 1 < total && expanded_terrain_types[index + 1] == "grass") {
|
||||
while (index + 1 < total) {
|
||||
string nextTerrain = expanded_terrain_types[index + 1];
|
||||
if (nextTerrain.find("mountain:") == 0) {
|
||||
nextTerrain = nextTerrain.substr(9);
|
||||
}
|
||||
if (nextTerrain != terrain) break;
|
||||
index++;
|
||||
}
|
||||
int segmentEnd = index;
|
||||
@@ -306,7 +361,8 @@ void get_grass_areas(int[]@ areaStarts, int[]@ areaEnds) {
|
||||
|
||||
bool relocate_tree_to_any_area(Tree@ tree, int[]@ areaStarts, int[]@ areaEnds) {
|
||||
for (uint i = 0; i < areaStarts.length(); i++) {
|
||||
if (count_trees_in_area(areaStarts[i], areaEnds[i], tree) >= TREE_MAX_PER_AREA) continue;
|
||||
int maxTrees = get_tree_max_for_area(areaStarts[i], areaEnds[i]);
|
||||
if (count_trees_in_area(areaStarts[i], areaEnds[i], tree) >= maxTrees) continue;
|
||||
if (place_tree_in_area(tree, areaStarts[i], areaEnds[i])) {
|
||||
return true;
|
||||
}
|
||||
@@ -317,13 +373,14 @@ bool relocate_tree_to_any_area(Tree@ tree, int[]@ areaStarts, int[]@ areaEnds) {
|
||||
void normalize_tree_positions() {
|
||||
int[] areaStarts;
|
||||
int[] areaEnds;
|
||||
get_grass_areas(areaStarts, areaEnds);
|
||||
get_tree_areas(areaStarts, areaEnds);
|
||||
if (areaStarts.length() == 0) return;
|
||||
|
||||
for (uint i = 0; i < trees.length(); i++) {
|
||||
int areaStart = 0;
|
||||
int areaEnd = 0;
|
||||
if (!get_tree_area_bounds_for_position(trees[i].position, areaStart, areaEnd)) {
|
||||
string areaTerrain = "";
|
||||
if (!get_tree_area_bounds_for_position(trees[i].position, areaStart, areaEnd, areaTerrain)) {
|
||||
if (!relocate_tree_to_any_area(trees[i], areaStarts, areaEnds)) {
|
||||
if (trees[i].sound_handle != -1) {
|
||||
p.destroy_sound(trees[i].sound_handle);
|
||||
@@ -337,6 +394,7 @@ void normalize_tree_positions() {
|
||||
for (uint areaIndex = 0; areaIndex < areaStarts.length(); areaIndex++) {
|
||||
int areaStart = areaStarts[areaIndex];
|
||||
int areaEnd = areaEnds[areaIndex];
|
||||
int maxTrees = get_tree_max_for_area(areaStart, areaEnd);
|
||||
|
||||
int[] areaTreeIndices;
|
||||
for (uint i = 0; i < trees.length(); i++) {
|
||||
@@ -345,7 +403,7 @@ void normalize_tree_positions() {
|
||||
}
|
||||
}
|
||||
|
||||
while (areaTreeIndices.length() > TREE_MAX_PER_AREA) {
|
||||
while (areaTreeIndices.length() > maxTrees) {
|
||||
uint treeIndex = areaTreeIndices[areaTreeIndices.length() - 1];
|
||||
Tree@ tree = trees[treeIndex];
|
||||
if (!relocate_tree_to_any_area(tree, areaStarts, areaEnds)) {
|
||||
@@ -880,16 +938,16 @@ bool can_move_mountain(int from_x, int to_x) {
|
||||
if (mountain.is_steep_section(from_x, to_x)) {
|
||||
// Need rope
|
||||
if (get_personal_count(ITEM_ROPES) < 1) {
|
||||
speak_with_history("You'll need a rope to climb there.", true);
|
||||
speak_movement_blocked("You'll need a rope to climb there.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prompt for rope climb
|
||||
int elevation_change = mountain.get_elevation_change(from_x, to_x);
|
||||
if (elevation_change > 0) {
|
||||
speak_with_history("Press up to climb up.", true);
|
||||
speak_movement_blocked("Press up to climb up.");
|
||||
} else {
|
||||
speak_with_history("Press down to climb down.", true);
|
||||
speak_movement_blocked("Press down to climb down.");
|
||||
}
|
||||
|
||||
// Store pending rope climb info
|
||||
@@ -901,6 +959,27 @@ bool can_move_mountain(int from_x, int to_x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool can_enter_stream_tile(int pos) {
|
||||
if (!is_deep_stream_at(pos)) return true;
|
||||
if (get_personal_count(ITEM_CANOES) > 0) return true;
|
||||
speak_movement_blocked("You need a canoe to cross deep water.");
|
||||
return false;
|
||||
}
|
||||
|
||||
timer movementBlockTimer;
|
||||
string lastMovementBlockMessage = "";
|
||||
const int MOVEMENT_BLOCK_COOLDOWN_MS = 3000;
|
||||
|
||||
void speak_movement_blocked(string message) {
|
||||
if (message == lastMovementBlockMessage && movementBlockTimer.elapsed < MOVEMENT_BLOCK_COOLDOWN_MS) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastMovementBlockMessage = message;
|
||||
movementBlockTimer.restart();
|
||||
speak_with_history(message, true);
|
||||
}
|
||||
|
||||
// Rope climbing functions
|
||||
void start_rope_climb(bool climbing_up, int target_x, int target_elevation) {
|
||||
rope_climbing = true;
|
||||
|
||||
@@ -36,7 +36,8 @@ const int ITEM_BOWSTRINGS = 30;
|
||||
const int ITEM_SINEW = 31;
|
||||
const int ITEM_BOAR_CARCASSES = 32;
|
||||
const int ITEM_BACKPACKS = 33;
|
||||
const int ITEM_COUNT = 34; // Total number of item types
|
||||
const int ITEM_CANOES = 34;
|
||||
const int ITEM_COUNT = 35; // Total number of item types
|
||||
|
||||
// Item definition class
|
||||
class ItemDefinition {
|
||||
@@ -116,6 +117,7 @@ void init_item_registry() {
|
||||
item_registry[ITEM_SINEW] = ItemDefinition(ITEM_SINEW, "sinew", "piece of sinew", "Sinew", 0.10);
|
||||
item_registry[ITEM_BOAR_CARCASSES] = ItemDefinition(ITEM_BOAR_CARCASSES, "boar carcasses", "boar carcass", "Boar Carcasses", 1.50);
|
||||
item_registry[ITEM_BACKPACKS] = ItemDefinition(ITEM_BACKPACKS, "backpacks", "backpack", "Backpacks", 2.50);
|
||||
item_registry[ITEM_CANOES] = ItemDefinition(ITEM_CANOES, "canoes", "canoe", "Canoes", 4.00);
|
||||
|
||||
// Define display order for inventory menus
|
||||
// This controls the order items appear in menus
|
||||
@@ -152,6 +154,7 @@ void init_item_registry() {
|
||||
ITEM_ROPES,
|
||||
ITEM_REED_BASKETS,
|
||||
ITEM_CLAY_POTS,
|
||||
ITEM_CANOES,
|
||||
// Clothing
|
||||
ITEM_SKIN_HATS,
|
||||
ITEM_SKIN_GLOVES,
|
||||
|
||||
@@ -71,6 +71,7 @@ void try_burn_incense() {
|
||||
}
|
||||
|
||||
add_personal_count(ITEM_INCENSE, -1);
|
||||
add_personal_count(ITEM_CLAY_POTS, -1);
|
||||
incense_hours_remaining += INCENSE_HOURS_PER_STICK;
|
||||
incense_burning = true;
|
||||
speak_with_history("Incense burning. " + incense_hours_remaining + " hours remaining.", true);
|
||||
|
||||
@@ -393,7 +393,6 @@ void update_time() {
|
||||
if (current_hour == 6) {
|
||||
process_daily_weapon_breakage();
|
||||
attempt_daily_quest();
|
||||
save_game_state();
|
||||
}
|
||||
attempt_daily_invasion();
|
||||
keep_base_fires_fed();
|
||||
@@ -404,6 +403,9 @@ void update_time() {
|
||||
attempt_blessing();
|
||||
check_weather_transition();
|
||||
attempt_resident_collection();
|
||||
if (current_hour == 6) {
|
||||
save_game_state();
|
||||
}
|
||||
}
|
||||
|
||||
ensure_ambience_running();
|
||||
|
||||
@@ -89,3 +89,9 @@ WorldStream@ get_stream_at(int pos) {
|
||||
bool is_position_in_water(int pos) {
|
||||
return get_stream_at(pos) != null;
|
||||
}
|
||||
|
||||
bool is_deep_stream_at(int pos) {
|
||||
WorldStream@ stream = get_stream_at(pos);
|
||||
if (stream == null) return false;
|
||||
return stream.get_width() > 3;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user