Initial commit.

This commit is contained in:
Storm Dragon
2026-01-17 22:51:22 -05:00
commit 4acd6edbf0
59 changed files with 3981 additions and 0 deletions
+456
View File
@@ -0,0 +1,456 @@
// Tree Object
class Tree {
int position;
int sticks;
int vines;
int health;
int height; // Height in feet
int sound_handle;
timer regen_timer;
bool depleted;
bool is_chopped;
int minutes_since_depletion; // Track minutes for gradual replenishment
Tree(int pos) {
position = pos;
depleted = false;
is_chopped = false;
sound_handle = -1;
minutes_since_depletion = 0;
refill();
}
void refill() {
sticks = random(2, 3);
vines = random(1, 2);
health = random(25, 40);
height = random(8, 30); // Random height between 8 and 30 feet
depleted = false;
is_chopped = false;
minutes_since_depletion = 0;
}
void respawn(int grass_start, int grass_end) {
if (sound_handle != -1) {
p.destroy_sound(sound_handle);
sound_handle = -1;
}
position = random(grass_start, grass_end);
refill();
}
void update() {
// Only play tree sound if not chopped and within 3 tiles distance (2 tiles on either side)
if (!is_chopped) {
if (abs(x - position) <= 3) {
if (sound_handle == -1 || !p.sound_is_active(sound_handle)) {
sound_handle = p.play_1d("sounds/environment/tree.ogg", x, position, true);
}
} else {
if (sound_handle != -1) {
p.destroy_sound(sound_handle);
sound_handle = -1;
}
}
}
}
void try_regen() {
// Skip if tree is fully stocked
if (!depleted && !is_chopped) return;
// Check every minute (60000ms)
if (regen_timer.elapsed < 60000) return;
// Advance to next minute
regen_timer.restart();
minutes_since_depletion++;
if (is_chopped) {
if (minutes_since_depletion >= 5) {
respawn(BASE_END + 1, GRASS_END);
}
return;
}
// At minute 5, completely refill
if (minutes_since_depletion >= 5) {
refill();
return;
}
// Skip if already fully stocked
if (sticks >= 3 && vines >= 2) {
depleted = false;
is_chopped = false;
return;
}
// Determine base chance based on minutes elapsed
int base_chance = 0;
if (minutes_since_depletion == 1) base_chance = 25;
else if (minutes_since_depletion == 2) base_chance = 50;
else if (minutes_since_depletion == 3) base_chance = 75;
else if (minutes_since_depletion == 4) base_chance = 100;
// Try to add items with decreasing probability
int current_chance = base_chance;
while (current_chance >= 25) {
// Check if we can add anything
if (sticks >= 3 && vines >= 2) break;
// Roll for success
int roll = random(1, 100);
if (roll <= current_chance) {
// Decide what to add (70% stick, 30% vine)
int item_roll = random(1, 100);
if (item_roll <= 70 && sticks < 3) {
// Add stick
sticks++;
} else if (vines < 2) {
// Add vine
vines++;
} else if (sticks < 3) {
// Vine is full but stick isn't, add stick
sticks++;
}
} else {
// Failed roll, stop trying
break;
}
// Reduce chance by 25% for next attempt (minimum 25%)
current_chance -= 25;
}
// Mark as no longer depleted if we have at least one item
if (sticks > 0 || vines > 0) {
depleted = false;
is_chopped = false;
}
}
}
Tree@[] trees;
void spawn_trees(int grass_start, int grass_end) {
int pos = random(grass_start, grass_end);
Tree@ t = Tree(pos);
trees.insert_last(t);
}
void update_environment() {
for(uint i = 0; i < trees.length(); i++) {
trees[i].update();
trees[i].try_regen();
}
}
Tree@ get_tree_at(int target_x) {
for(uint i=0; i<trees.length(); i++) {
if(trees[i].position == target_x) {
return @trees[i];
}
}
return null;
}
void damage_tree(int target_x, int damage) {
Tree@ target = null;
for(uint i=0; i<trees.length(); i++) {
if(trees[i].position == target_x) {
@target = @trees[i];
break;
}
}
if(@target != null) {
if(!target.is_chopped) {
target.health -= damage;
p.play_stationary("sounds/weapons/axe_hit.ogg", false);
if(target.health <= 0) {
target.is_chopped = true;
target.depleted = true;
target.regen_timer.restart();
target.minutes_since_depletion = 0;
// Stop the looping sound
if (target.sound_handle != -1) {
p.destroy_sound(target.sound_handle);
target.sound_handle = -1;
}
// Play the falling sound at the tree's position
p.play_1d("sounds/items/tree.ogg", x, target.position, false);
int sticks_dropped = random(1, 3);
int vines_dropped = random(1, 2);
int sticks_added = add_to_stack(inv_sticks, sticks_dropped);
int vines_added = add_to_stack(inv_vines, vines_dropped);
int logs_added = add_to_stack(inv_logs, 1);
inv_sticks += sticks_added;
inv_vines += vines_added;
inv_logs += logs_added;
string drop_message = "Tree fell!";
if (sticks_added > 0 || vines_added > 0 || logs_added > 0) {
string log_label = (logs_added == 1) ? " log" : " logs";
drop_message += " Got " + sticks_added + " sticks, " + vines_added + " vines, and " + logs_added + log_label + ".";
}
if (sticks_added < sticks_dropped || vines_added < vines_dropped || logs_added < 1) {
drop_message += " Inventory full.";
}
p.play_stationary("sounds/items/stick.ogg", false);
screen_reader_speak(drop_message, true);
}
}
}
}
void perform_search(int current_x)
{
// Check for Snares nearby (Current or Adjacent)
// "Shift beside the snare will collect the snare" -> adjacent
// We check current and +/- 1
for (int check_x = current_x - 1; check_x <= current_x + 1; check_x++) {
// Skip current x? User said "beside". If on top, it breaks.
// But if I stand adjacent and shift...
if (check_x == current_x) continue; // Safety against collecting own snare you stand on? (Collision happens on move)
// Actually, collision happens when *moving onto* it. If you placed it, you are on it.
// If active is false (just placed), you can pick it up.
// If active is true (you moved away), moving back breaks it.
// So checking adjacent is correct.
WorldSnare@ s = get_snare_at(check_x);
if (s != null) {
if (s.has_catch) {
if (inv_small_game >= MAX_ITEM_STACK) {
screen_reader_speak("You can't carry any more small game.", true);
return;
}
if (inv_snares >= MAX_ITEM_STACK) {
screen_reader_speak("You can't carry any more snares.", true);
return;
}
inv_small_game++;
inv_small_game_types.insert_last(s.catch_type);
inv_snares++; // Recover snare
screen_reader_speak("Collected " + s.catch_type + " and snare.", true);
} else {
if (inv_snares >= MAX_ITEM_STACK) {
screen_reader_speak("You can't carry any more snares.", true);
return;
}
inv_snares++; // Recover snare
screen_reader_speak("Collected snare.", true);
}
p.play_stationary("sounds/items/miscellaneous.ogg", false);
remove_snare_at(check_x);
return; // Action taken, stop searching
}
}
// Gravel Area - Stones (20-34)
if (current_x >= 20 && current_x <= 34)
{
if (inv_stones < MAX_ITEM_STACK)
{
inv_stones++;
p.play_stationary("sounds/items/stone.ogg", false);
screen_reader_speak("Found a stone.", true);
}
else
{
screen_reader_speak("You can't carry any more stones.", true);
}
return;
}
// Grass Area - Trees (Sticks/Vines) (5-19)
if (current_x >= 5 && current_x <= 19)
{
Tree@ nearest = null;
for(uint i=0; i<trees.length(); i++)
{
if(trees[i].position >= current_x - 1 && trees[i].position <= current_x + 1)
{
@nearest = @trees[i];
break;
}
}
if(@nearest != null)
{
if(nearest.is_chopped) {
screen_reader_speak("This tree has been cut down.", true);
return;
}
if (nearest.depleted) {
screen_reader_speak("This tree is empty.", true);
return;
}
if(nearest.sticks > 0 || nearest.vines > 0)
{
bool find_stick = (nearest.vines <= 0) || (nearest.sticks > 0 && random(0, 1) == 0);
if(find_stick)
{
if (inv_sticks >= MAX_ITEM_STACK) {
screen_reader_speak("You can't carry any more sticks.", true);
return;
}
nearest.sticks--;
inv_sticks++;
p.play_stationary("sounds/items/stick.ogg", false);
screen_reader_speak("Found a stick.", true);
}
else
{
if (inv_vines >= MAX_ITEM_STACK) {
screen_reader_speak("You can't carry any more vines.", true);
return;
}
nearest.vines--;
inv_vines++;
p.play_stationary("sounds/items/vine.ogg", false);
screen_reader_speak("Found a vine.", true);
}
if(nearest.sticks == 0 && nearest.vines == 0) {
nearest.depleted = true;
nearest.regen_timer.restart();
nearest.minutes_since_depletion = 0;
}
}
else
{
screen_reader_speak("This area has nothing left.", true);
}
}
else
{
screen_reader_speak("Found nothing.", true);
}
return;
}
screen_reader_speak("Found nothing.", true);
}
// Climbing functions
void start_climbing_tree(int target_x) {
Tree@ tree = get_tree_at(target_x);
if (tree == null || tree.is_chopped) {
return;
}
climbing = true;
climb_target_y = tree.height;
climb_timer.restart();
screen_reader_speak("Started climbing tree. Height is " + tree.height + " feet.", true);
}
void update_climbing() {
if (!climbing) return;
// Climb at 1 foot per 500ms
if (climb_timer.elapsed > 500) {
climb_timer.restart();
// Climbing up
if (y < climb_target_y) {
y++;
p.play_stationary("sounds/actions/climb_tree.ogg", false);
if (y >= climb_target_y) {
climbing = false;
screen_reader_speak("Reached the top at " + y + " feet.", true);
}
}
// Climbing down
else if (y > climb_target_y) {
y--;
p.play_stationary("sounds/actions/climb_tree.ogg", false);
if (y <= 0) {
climbing = false;
y = 0;
screen_reader_speak("Safely reached the ground.", true);
}
}
}
}
void climb_down_tree() {
if (y == 0 || climbing) return;
climbing = true;
climb_target_y = 0;
climb_timer.restart();
screen_reader_speak("Climbing down.", true);
}
void start_falling() {
if (y <= 0 || falling) return;
falling = true;
fall_start_y = y; // Remember where we started falling from
fall_timer.restart();
// Start looping falling sound
fall_sound_handle = p.play_stationary("sounds/actions/falling.ogg", true);
}
void update_falling() {
if (!falling) return;
// Fall faster than climbing - 1 foot per 100ms
if (fall_timer.elapsed > 100) {
fall_timer.restart();
if (y > 0) {
y--;
// Restart falling sound with decreasing pitch each foot
if (fall_sound_handle != -1) {
p.destroy_sound(fall_sound_handle);
}
// Pitch ranges from 100 (high up) to 50 (near ground)
// Calculate based on current y position
float pitch_percent = 50.0 + (50.0 * (y / 30.0));
if (pitch_percent < 50.0) pitch_percent = 50.0;
if (pitch_percent > 100.0) pitch_percent = 100.0;
fall_sound_handle = p.play_stationary_extended("sounds/actions/falling.ogg", true, 0, 0, 0, pitch_percent);
} else {
// Hit the ground
falling = false;
// Stop falling sound
if (fall_sound_handle != -1) {
p.destroy_sound(fall_sound_handle);
fall_sound_handle = -1;
}
p.play_stationary("sounds/actions/hit_ground.ogg", false);
// Calculate fall damage
int fall_height = fall_start_y;
if (fall_height > 10) {
int damage = 0;
for (int i = 10; i < fall_height; i++) {
damage += random(1, 3);
}
player_health -= damage;
screen_reader_speak("Fell " + fall_height + " feet! Took " + damage + " damage. " + player_health + " health remaining.", true);
} else {
screen_reader_speak("Landed safely.", true);
}
fall_start_y = 0;
}
}
}