Various bug fixes.
This commit is contained in:
+8
-14
@@ -10,9 +10,7 @@ class Bandit {
|
||||
string weapon_type; // "spear" or "axe"
|
||||
int sound_handle;
|
||||
timer move_timer;
|
||||
timer alert_timer;
|
||||
timer attack_timer;
|
||||
int next_alert_delay;
|
||||
int move_interval;
|
||||
|
||||
// Wandering behavior properties
|
||||
@@ -38,9 +36,7 @@ class Bandit {
|
||||
move_interval = random(BANDIT_MOVE_INTERVAL_MIN, BANDIT_MOVE_INTERVAL_MAX);
|
||||
|
||||
move_timer.restart();
|
||||
alert_timer.restart();
|
||||
attack_timer.restart();
|
||||
next_alert_delay = random(BANDIT_ALERT_MIN_DELAY, BANDIT_ALERT_MAX_DELAY);
|
||||
|
||||
// Initialize wandering behavior (start aggressive during invasion)
|
||||
behavior_state = "aggressive";
|
||||
@@ -87,7 +83,8 @@ void spawn_bandit(int expansion_start, int expansion_end) {
|
||||
|
||||
Bandit@ b = Bandit(spawn_x, expansion_start, expansion_end);
|
||||
bandits.insert_last(b);
|
||||
b.sound_handle = play_creature_voice(b.alert_sound, x, spawn_x, BANDIT_SOUND_VOLUME_STEP);
|
||||
// Play looping sound that follows the bandit
|
||||
b.sound_handle = play_1d_with_volume_step(b.alert_sound, x, spawn_x, true, BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
bool can_bandit_attack_player(Bandit@ bandit) {
|
||||
@@ -177,18 +174,15 @@ void try_attack_barricade_bandit(Bandit@ bandit) {
|
||||
}
|
||||
|
||||
void update_bandit(Bandit@ bandit) {
|
||||
// Play alert sound at intervals
|
||||
if (bandit.alert_timer.elapsed > bandit.next_alert_delay) {
|
||||
bandit.alert_timer.restart();
|
||||
bandit.next_alert_delay = random(BANDIT_ALERT_MIN_DELAY, BANDIT_ALERT_MAX_DELAY);
|
||||
|
||||
// Destroy old sound handle before playing new one to prevent overlapping
|
||||
// Update looping sound position
|
||||
if (bandit.sound_handle != -1 && p.sound_is_active(bandit.sound_handle)) {
|
||||
p.update_sound_1d(bandit.sound_handle, bandit.position);
|
||||
} else if (bandit.sound_handle == -1 || !p.sound_is_active(bandit.sound_handle)) {
|
||||
// Restart looping sound if it stopped
|
||||
if (bandit.sound_handle != -1) {
|
||||
p.destroy_sound(bandit.sound_handle);
|
||||
bandit.sound_handle = -1;
|
||||
}
|
||||
|
||||
bandit.sound_handle = play_creature_voice(bandit.alert_sound, x, bandit.position, BANDIT_SOUND_VOLUME_STEP);
|
||||
bandit.sound_handle = play_1d_with_volume_step(bandit.alert_sound, x, bandit.position, true, BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
if (try_attack_player_bandit(bandit)) {
|
||||
|
||||
@@ -38,10 +38,8 @@ class FlyingCreature {
|
||||
int sound_handle;
|
||||
int fall_sound_handle;
|
||||
timer move_timer;
|
||||
timer sound_timer;
|
||||
timer fall_timer;
|
||||
int next_move_delay;
|
||||
int next_sound_delay;
|
||||
string voice_sound;
|
||||
bool fading_out;
|
||||
bool ready_to_remove;
|
||||
@@ -63,10 +61,8 @@ class FlyingCreature {
|
||||
}
|
||||
|
||||
move_timer.restart();
|
||||
sound_timer.restart();
|
||||
|
||||
next_move_delay = random(cfg.move_interval_min, cfg.move_interval_max);
|
||||
next_sound_delay = random(cfg.sound_delay_min, cfg.sound_delay_max);
|
||||
fading_out = false;
|
||||
ready_to_remove = false;
|
||||
}
|
||||
@@ -229,7 +225,8 @@ bool spawn_flying_creature(string creature_type) {
|
||||
|
||||
FlyingCreature@ c = FlyingCreature(creature_type, spawn_x, area_start, area_end, cfg);
|
||||
flying_creatures.insert_last(c);
|
||||
c.sound_handle = play_creature_voice(c.voice_sound, x, spawn_x, cfg.sound_volume_step);
|
||||
// Play looping sound that follows the flying creature
|
||||
c.sound_handle = play_1d_with_volume_step(c.voice_sound, x, spawn_x, true, cfg.sound_volume_step);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -267,10 +264,15 @@ void update_flying_creature(FlyingCreature@ creature) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (creature.sound_timer.elapsed > creature.next_sound_delay) {
|
||||
creature.sound_timer.restart();
|
||||
creature.next_sound_delay = random(cfg.sound_delay_min, cfg.sound_delay_max);
|
||||
creature.sound_handle = play_creature_voice(creature.voice_sound, x, creature.position, cfg.sound_volume_step);
|
||||
// Update looping sound position
|
||||
if (creature.sound_handle != -1 && p.sound_is_active(creature.sound_handle)) {
|
||||
p.update_sound_1d(creature.sound_handle, creature.position);
|
||||
} else if (creature.sound_handle == -1 || !p.sound_is_active(creature.sound_handle)) {
|
||||
// Restart looping sound if it stopped
|
||||
if (creature.sound_handle != -1) {
|
||||
p.destroy_sound(creature.sound_handle);
|
||||
}
|
||||
creature.sound_handle = play_1d_with_volume_step(creature.voice_sound, x, creature.position, true, cfg.sound_volume_step);
|
||||
}
|
||||
|
||||
if (cfg.fly_away_chance > 0 && random(1, 1000) <= cfg.fly_away_chance) {
|
||||
|
||||
@@ -8,10 +8,8 @@ class GroundGame {
|
||||
int health;
|
||||
int sound_handle;
|
||||
timer move_timer;
|
||||
timer sound_timer;
|
||||
timer attack_timer;
|
||||
int next_move_delay;
|
||||
int next_sound_delay;
|
||||
string voice_sound;
|
||||
string state; // "wandering" or "charging"
|
||||
int area_start;
|
||||
@@ -32,11 +30,9 @@ class GroundGame {
|
||||
voice_sound = ground_game_boar_sounds[random(0, ground_game_boar_sounds.length() - 1)];
|
||||
|
||||
move_timer.restart();
|
||||
sound_timer.restart();
|
||||
attack_timer.restart();
|
||||
|
||||
next_move_delay = random(BOAR_MOVE_INTERVAL_MIN, BOAR_MOVE_INTERVAL_MAX);
|
||||
next_sound_delay = random(BOAR_SOUND_MIN_DELAY, BOAR_SOUND_MAX_DELAY);
|
||||
}
|
||||
}
|
||||
GroundGame@[] ground_games;
|
||||
@@ -80,7 +76,8 @@ void spawn_ground_game(int expansion_start, int expansion_end) {
|
||||
|
||||
GroundGame@ b = GroundGame(spawn_x, expansion_start, expansion_end, "boar");
|
||||
ground_games.insert_last(b);
|
||||
b.sound_handle = play_creature_voice(b.voice_sound, x, spawn_x, BOAR_SOUND_VOLUME_STEP);
|
||||
// Play looping sound that follows the boar
|
||||
b.sound_handle = play_1d_with_volume_step(b.voice_sound, x, spawn_x, true, BOAR_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
bool can_ground_game_attack_player(GroundGame@ game) {
|
||||
@@ -113,12 +110,15 @@ bool try_attack_player_ground_game(GroundGame@ game) {
|
||||
}
|
||||
|
||||
void update_ground_game(GroundGame@ game) {
|
||||
// Sound logic
|
||||
if (game.sound_timer.elapsed > game.next_sound_delay) {
|
||||
game.sound_timer.restart();
|
||||
game.next_sound_delay = random(BOAR_SOUND_MIN_DELAY, BOAR_SOUND_MAX_DELAY);
|
||||
// Only play if wandering or occasionally while charging
|
||||
game.sound_handle = play_creature_voice(game.voice_sound, x, game.position, BOAR_SOUND_VOLUME_STEP);
|
||||
// Update looping sound position
|
||||
if (game.sound_handle != -1 && p.sound_is_active(game.sound_handle)) {
|
||||
p.update_sound_1d(game.sound_handle, game.position);
|
||||
} else if (game.sound_handle == -1 || !p.sound_is_active(game.sound_handle)) {
|
||||
// Restart looping sound if it stopped for some reason
|
||||
if (game.sound_handle != -1) {
|
||||
p.destroy_sound(game.sound_handle);
|
||||
}
|
||||
game.sound_handle = play_1d_with_volume_step(game.voice_sound, x, game.position, true, BOAR_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
// Combat logic
|
||||
|
||||
+8
-13
@@ -10,9 +10,7 @@ class Undead {
|
||||
string voice_sound;
|
||||
int sound_handle;
|
||||
timer move_timer;
|
||||
timer groan_timer;
|
||||
timer attack_timer;
|
||||
int next_groan_delay;
|
||||
|
||||
Undead(int pos, string type = "zombie") {
|
||||
position = pos;
|
||||
@@ -22,9 +20,7 @@ class Undead {
|
||||
voice_sound = undead_zombie_sounds[sound_index];
|
||||
sound_handle = -1;
|
||||
move_timer.restart();
|
||||
groan_timer.restart();
|
||||
attack_timer.restart();
|
||||
next_groan_delay = random(ZOMBIE_GROAN_MIN_DELAY, ZOMBIE_GROAN_MAX_DELAY);
|
||||
}
|
||||
}
|
||||
Undead@[] undeads;
|
||||
@@ -65,7 +61,8 @@ void spawn_undead() {
|
||||
|
||||
Undead@ z = Undead(spawn_x, "zombie");
|
||||
undeads.insert_last(z);
|
||||
z.sound_handle = play_creature_voice(z.voice_sound, x, spawn_x, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
// Play looping sound that follows the zombie
|
||||
z.sound_handle = play_1d_with_volume_step(z.voice_sound, x, spawn_x, true, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
void try_attack_barricade_undead(Undead@ undead) {
|
||||
@@ -131,17 +128,15 @@ bool try_attack_player_undead(Undead@ undead) {
|
||||
}
|
||||
|
||||
void update_undead(Undead@ undead) {
|
||||
if (undead.groan_timer.elapsed > undead.next_groan_delay) {
|
||||
undead.groan_timer.restart();
|
||||
undead.next_groan_delay = random(ZOMBIE_GROAN_MIN_DELAY, ZOMBIE_GROAN_MAX_DELAY);
|
||||
|
||||
// Destroy old sound handle before playing new one to prevent overlapping
|
||||
// Update looping sound position
|
||||
if (undead.sound_handle != -1 && p.sound_is_active(undead.sound_handle)) {
|
||||
p.update_sound_1d(undead.sound_handle, undead.position);
|
||||
} else if (undead.sound_handle == -1 || !p.sound_is_active(undead.sound_handle)) {
|
||||
// Restart looping sound if it stopped for some reason
|
||||
if (undead.sound_handle != -1) {
|
||||
p.destroy_sound(undead.sound_handle);
|
||||
undead.sound_handle = -1;
|
||||
}
|
||||
|
||||
undead.sound_handle = play_creature_voice(undead.voice_sound, x, undead.position, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
undead.sound_handle = play_1d_with_volume_step(undead.voice_sound, x, undead.position, true, ZOMBIE_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
if (try_attack_player_undead(undead)) {
|
||||
|
||||
+20
-13
@@ -558,23 +558,30 @@ void perform_search(int current_x)
|
||||
return;
|
||||
}
|
||||
|
||||
// Trees (Sticks/Vines) - Check for nearby tree anywhere
|
||||
// Trees (Sticks/Vines) - Check for nearby tree, but only on non-stone terrain
|
||||
// Skip tree search if player is on stone terrain (prioritize stone finding)
|
||||
string search_terrain = get_terrain_at_position(current_x);
|
||||
bool skip_tree_search = (search_terrain == "stone" || search_terrain == "gravel" ||
|
||||
search_terrain == "snow" || search_terrain == "hard_stone");
|
||||
|
||||
Tree@ nearest = null;
|
||||
int nearest_distance = 999;
|
||||
for(uint i=0; i<trees.length(); i++)
|
||||
{
|
||||
int distance = trees[i].position - current_x;
|
||||
if (distance < 0) distance = -distance;
|
||||
if(distance <= 1 && distance < nearest_distance)
|
||||
if (!skip_tree_search) {
|
||||
for(uint i=0; i<trees.length(); i++)
|
||||
{
|
||||
nearest_distance = distance;
|
||||
@nearest = @trees[i];
|
||||
if (nearest_distance == 0) {
|
||||
break;
|
||||
int distance = trees[i].position - current_x;
|
||||
if (distance < 0) distance = -distance;
|
||||
if(distance <= 1 && distance < nearest_distance)
|
||||
{
|
||||
nearest_distance = distance;
|
||||
@nearest = @trees[i];
|
||||
if (nearest_distance == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(@nearest != null)
|
||||
{
|
||||
if(nearest.is_chopped) {
|
||||
@@ -659,7 +666,7 @@ void perform_search(int current_x)
|
||||
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") {
|
||||
if (terrain == "stone" || terrain == "hard_stone" || terrain == "gravel") {
|
||||
is_stone_terrain = true;
|
||||
}
|
||||
} else {
|
||||
@@ -671,7 +678,7 @@ void perform_search(int current_x)
|
||||
if (terrain.find("mountain:") == 0) {
|
||||
terrain = terrain.substr(9);
|
||||
}
|
||||
if (terrain == "stone" || terrain == "hard_stone") {
|
||||
if (terrain == "stone" || terrain == "hard_stone" || terrain == "gravel") {
|
||||
is_stone_terrain = true;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-11
@@ -177,17 +177,18 @@ string get_equipment_name(int equip_type) {
|
||||
}
|
||||
|
||||
bool equipment_available(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR) return inv_spears > 0;
|
||||
if (equip_type == EQUIP_AXE) return inv_axes > 0;
|
||||
if (equip_type == EQUIP_SLING) return inv_slings > 0;
|
||||
if (equip_type == EQUIP_BOW) return inv_bows > 0;
|
||||
if (equip_type == EQUIP_HAT) return inv_skin_hats > 0;
|
||||
if (equip_type == EQUIP_GLOVES) return inv_skin_gloves > 0;
|
||||
if (equip_type == EQUIP_PANTS) return inv_skin_pants > 0;
|
||||
if (equip_type == EQUIP_TUNIC) return inv_skin_tunics > 0;
|
||||
if (equip_type == EQUIP_MOCCASINS) return inv_moccasins > 0;
|
||||
if (equip_type == EQUIP_POUCH) return inv_skin_pouches > 0;
|
||||
if (equip_type == EQUIP_BACKPACK) return inv_backpacks > 0;
|
||||
// Check unruned items first
|
||||
if (equip_type == EQUIP_SPEAR) return inv_spears > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_AXE) return inv_axes > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_SLING) return inv_slings > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_BOW) return inv_bows > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_HAT) return inv_skin_hats > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_GLOVES) return inv_skin_gloves > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_PANTS) return inv_skin_pants > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_TUNIC) return inv_skin_tunics > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_MOCCASINS) return inv_moccasins > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_POUCH) return inv_skin_pouches > 0 || has_any_runed_version(equip_type);
|
||||
if (equip_type == EQUIP_BACKPACK) return inv_backpacks > 0 || has_any_runed_version(equip_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ void check_altar_menu(int player_x) {
|
||||
}
|
||||
|
||||
void sacrifice_item(int item_type) {
|
||||
if (item_type == -2 || is_runed_item_type(item_type)) {
|
||||
speak_with_history("Runed items cannot be sacrificed.", true);
|
||||
return;
|
||||
}
|
||||
int available = get_personal_count(item_type);
|
||||
if (available <= 0) {
|
||||
speak_with_history("Nothing to sacrifice.", true);
|
||||
@@ -66,6 +70,10 @@ void sacrifice_item(int item_type) {
|
||||
}
|
||||
|
||||
void sacrifice_item_max(int item_type) {
|
||||
if (item_type == -2 || is_runed_item_type(item_type)) {
|
||||
speak_with_history("Runed items cannot be sacrificed.", true);
|
||||
return;
|
||||
}
|
||||
int available = get_personal_count(item_type);
|
||||
if (available <= 0) {
|
||||
speak_with_history("Nothing to sacrifice.", true);
|
||||
|
||||
@@ -32,6 +32,19 @@ void build_personal_inventory_options(string[]@ options, int[]@ item_types) {
|
||||
options.insert_last("Moccasins: " + inv_moccasins); item_types.insert_last(ITEM_MOCCASINS);
|
||||
options.insert_last("Skin Pouches: " + inv_skin_pouches); item_types.insert_last(ITEM_SKIN_POUCHES);
|
||||
options.insert_last("Backpacks: " + inv_backpacks); item_types.insert_last(ITEM_BACKPACKS);
|
||||
|
||||
// Add runed items
|
||||
int[] runeable = get_runeable_equipment_types();
|
||||
for (uint i = 0; i < runeable.length(); i++) {
|
||||
int equip_type = runeable[i];
|
||||
// For now, only check for Swiftness rune
|
||||
int count = get_runed_item_count(equip_type, RUNE_SWIFTNESS);
|
||||
if (count > 0) {
|
||||
string name = "Runed " + get_base_equipment_name(equip_type) + " of Quickness";
|
||||
options.insert_last(name + ": " + count);
|
||||
item_types.insert_last(encode_runed_item_type(equip_type, RUNE_SWIFTNESS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void show_inventory() {
|
||||
@@ -50,6 +63,21 @@ void show_inventory() {
|
||||
info += inv_incense + " incense. ";
|
||||
info += "Tools: " + inv_spears + " spears, " + inv_slings + " slings, " + inv_axes + " axes, " + inv_snares + " snares, " + inv_knives + " knives, " + inv_fishing_poles + " fishing poles, " + inv_ropes + " ropes, " + inv_reed_baskets + " reed baskets, " + inv_clay_pots + " clay pots. ";
|
||||
info += "Clothing: " + inv_skin_hats + " hats, " + inv_skin_gloves + " gloves, " + inv_skin_pants + " pants, " + inv_skin_tunics + " tunics, " + inv_moccasins + " moccasins, " + inv_skin_pouches + " skin pouches.";
|
||||
|
||||
// Add runed items summary
|
||||
string runed_info = "";
|
||||
int[] runeable = get_runeable_equipment_types();
|
||||
for (uint i = 0; i < runeable.length(); i++) {
|
||||
int count = get_runed_item_count(runeable[i], RUNE_SWIFTNESS);
|
||||
if (count > 0) {
|
||||
if (runed_info.length() > 0) runed_info += ", ";
|
||||
runed_info += count + " Runed " + get_base_equipment_name(runeable[i]) + " of Quickness";
|
||||
}
|
||||
}
|
||||
if (runed_info.length() > 0) {
|
||||
info += " Runed items: " + runed_info + ".";
|
||||
}
|
||||
|
||||
speak_with_history(info, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,44 @@ int prompt_transfer_amount(const string prompt, int max_amount) {
|
||||
return amount;
|
||||
}
|
||||
|
||||
// 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
|
||||
int encode_runed_item_type(int equip_type, int rune_type) {
|
||||
return -1000 - (equip_type * 10) - rune_type;
|
||||
}
|
||||
|
||||
// Decode a runed item type back to equip_type and rune_type
|
||||
void decode_runed_item_type(int encoded, int& out equip_type, int& out rune_type) {
|
||||
int decoded = -(encoded + 1000);
|
||||
equip_type = decoded / 10;
|
||||
rune_type = decoded % 10;
|
||||
}
|
||||
|
||||
// Check if an item_type represents a runed item
|
||||
bool is_runed_item_type(int item_type) {
|
||||
return item_type <= -1000;
|
||||
}
|
||||
|
||||
void deposit_item(int item_type) {
|
||||
// Handle runed items
|
||||
if (is_runed_item_type(item_type)) {
|
||||
int equip_type, rune_type;
|
||||
decode_runed_item_type(item_type, equip_type, rune_type);
|
||||
if (deposit_runed_item(equip_type, rune_type)) {
|
||||
string name = "Runed " + get_base_equipment_name(equip_type) + " of " + get_rune_effect_name(rune_type);
|
||||
cleanup_equipment_after_inventory_change();
|
||||
speak_with_history("Deposited " + name + ".", true);
|
||||
} else {
|
||||
speak_with_history("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);
|
||||
return;
|
||||
}
|
||||
int available = get_personal_count(item_type);
|
||||
if (available <= 0) {
|
||||
speak_with_history("Nothing to deposit.", true);
|
||||
@@ -80,6 +117,30 @@ void deposit_item(int item_type) {
|
||||
}
|
||||
|
||||
void deposit_item_max(int item_type) {
|
||||
// Handle runed items
|
||||
if (is_runed_item_type(item_type)) {
|
||||
int equip_type, rune_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);
|
||||
return;
|
||||
}
|
||||
int count = 0;
|
||||
while (get_runed_item_count(equip_type, rune_type) > 0) {
|
||||
deposit_runed_item(equip_type, rune_type);
|
||||
count++;
|
||||
}
|
||||
string name = "Runed " + get_base_equipment_name(equip_type) + " of " + get_rune_effect_name(rune_type);
|
||||
cleanup_equipment_after_inventory_change();
|
||||
speak_with_history("Deposited " + count + " " + name + ".", true);
|
||||
return;
|
||||
}
|
||||
// Handle legacy -2 marker
|
||||
if (item_type == -2) {
|
||||
speak_with_history("Runed items cannot be deposited into storage.", true);
|
||||
return;
|
||||
}
|
||||
int available = get_personal_count(item_type);
|
||||
if (available <= 0) {
|
||||
speak_with_history("Nothing to deposit.", true);
|
||||
@@ -128,6 +189,18 @@ void deposit_item_max(int item_type) {
|
||||
}
|
||||
|
||||
void withdraw_item(int item_type) {
|
||||
// Handle runed items
|
||||
if (is_runed_item_type(item_type)) {
|
||||
int equip_type, rune_type;
|
||||
decode_runed_item_type(item_type, equip_type, rune_type);
|
||||
if (withdraw_runed_item(equip_type, rune_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);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int available = get_storage_count(item_type);
|
||||
if (available <= 0) {
|
||||
speak_with_history("Nothing to withdraw.", true);
|
||||
@@ -175,6 +248,24 @@ void withdraw_item(int item_type) {
|
||||
}
|
||||
|
||||
void withdraw_item_max(int item_type) {
|
||||
// Handle runed items
|
||||
if (is_runed_item_type(item_type)) {
|
||||
int equip_type, rune_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);
|
||||
return;
|
||||
}
|
||||
int count = 0;
|
||||
while (get_stored_runed_item_count(equip_type, rune_type) > 0) {
|
||||
withdraw_runed_item(equip_type, rune_type);
|
||||
count++;
|
||||
}
|
||||
string name = "Runed " + get_base_equipment_name(equip_type) + " of " + get_rune_effect_name(rune_type);
|
||||
speak_with_history("Withdrew " + count + " " + name + ".", true);
|
||||
return;
|
||||
}
|
||||
int available = get_storage_count(item_type);
|
||||
if (available <= 0) {
|
||||
speak_with_history("Nothing to withdraw.", true);
|
||||
@@ -255,6 +346,18 @@ void build_storage_inventory_options(string[]@ options, int[]@ item_types) {
|
||||
options.insert_last("Moccasins: " + storage_moccasins); item_types.insert_last(ITEM_MOCCASINS);
|
||||
options.insert_last("Skin Pouches: " + storage_skin_pouches); item_types.insert_last(ITEM_SKIN_POUCHES);
|
||||
options.insert_last("Backpacks: " + storage_backpacks); item_types.insert_last(ITEM_BACKPACKS);
|
||||
|
||||
// Add stored runed items
|
||||
int[] runeable = get_runeable_equipment_types();
|
||||
for (uint i = 0; i < runeable.length(); i++) {
|
||||
int equip_type = runeable[i];
|
||||
int count = get_stored_runed_item_count(equip_type, RUNE_SWIFTNESS);
|
||||
if (count > 0) {
|
||||
string name = "Runed " + get_base_equipment_name(equip_type) + " of Quickness";
|
||||
options.insert_last(name + ": " + count);
|
||||
item_types.insert_last(encode_runed_item_type(equip_type, RUNE_SWIFTNESS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void run_storage_menu() {
|
||||
|
||||
+10
-7
@@ -93,16 +93,19 @@ void apply_quest_reward(int score) {
|
||||
int skins_added = add_to_stack(inv_skins, skins_gain);
|
||||
inv_skins += skins_added;
|
||||
|
||||
string message = "Quest reward: favor +" + format_favor(favor_gain) + ".";
|
||||
if (stones_gain > 0) message += " Stones +" + stones_added + ".";
|
||||
if (logs_gain > 0) message += " Logs +" + logs_added + ".";
|
||||
if (skins_gain > 0) message += " Skins +" + skins_added + ".";
|
||||
speak_with_history(message, true);
|
||||
string message = "Quest Complete!\n\nRewards:\n";
|
||||
message += "Favor: +" + format_favor(favor_gain) + "\n";
|
||||
if (stones_gain > 0) message += "Stones: +" + stones_added + "\n";
|
||||
if (logs_gain > 0) message += "Logs: +" + logs_added + "\n";
|
||||
if (skins_gain > 0) message += "Skins: +" + skins_added + "\n";
|
||||
message += "\nScore: " + score;
|
||||
text_reader(message, "Quest Rewards", true);
|
||||
}
|
||||
|
||||
void run_quest(int quest_type) {
|
||||
speak_with_history(get_quest_description(quest_type), true);
|
||||
wait(800);
|
||||
string quest_name = get_quest_name(quest_type);
|
||||
string quest_desc = get_quest_description(quest_type);
|
||||
text_reader(quest_name + "\n\n" + quest_desc, "Quest Instructions", true);
|
||||
p.pause_all();
|
||||
int score = 0;
|
||||
if (quest_type == QUEST_BAT_INVASION) score = run_bat_invasion();
|
||||
|
||||
@@ -22,6 +22,9 @@ const int RUNE_SWIFTNESS_GATHER_BONUS = 5;
|
||||
// Value: count of that runed item type
|
||||
dictionary runed_items;
|
||||
|
||||
// Dictionary for stored runed items (base storage)
|
||||
dictionary stored_runed_items;
|
||||
|
||||
// Track which rune is on equipped items
|
||||
int equipped_head_rune = RUNE_NONE;
|
||||
int equipped_torso_rune = RUNE_NONE;
|
||||
@@ -91,6 +94,51 @@ bool has_any_runed_version(int equip_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get count of stored runed items
|
||||
int get_stored_runed_item_count(int equip_type, int rune_type) {
|
||||
string key = make_runed_key(equip_type, rune_type);
|
||||
if (stored_runed_items.exists(key)) {
|
||||
return int(stored_runed_items[key]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add a runed item to storage
|
||||
void add_stored_runed_item(int equip_type, int rune_type) {
|
||||
string key = make_runed_key(equip_type, rune_type);
|
||||
int current = get_stored_runed_item_count(equip_type, rune_type);
|
||||
stored_runed_items.set(key, current + 1);
|
||||
}
|
||||
|
||||
// Remove a runed item from storage
|
||||
void remove_stored_runed_item(int equip_type, int rune_type) {
|
||||
string key = make_runed_key(equip_type, rune_type);
|
||||
int current = get_stored_runed_item_count(equip_type, rune_type);
|
||||
if (current > 0) {
|
||||
stored_runed_items.set(key, current - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Deposit runed item from personal inventory to storage
|
||||
bool deposit_runed_item(int equip_type, int rune_type) {
|
||||
int personal = get_runed_item_count(equip_type, rune_type);
|
||||
if (personal <= 0) return false;
|
||||
|
||||
remove_runed_item(equip_type, rune_type);
|
||||
add_stored_runed_item(equip_type, rune_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Withdraw runed item from storage to personal inventory
|
||||
bool withdraw_runed_item(int equip_type, int rune_type) {
|
||||
int stored = get_stored_runed_item_count(equip_type, rune_type);
|
||||
if (stored <= 0) return false;
|
||||
|
||||
remove_stored_runed_item(equip_type, rune_type);
|
||||
add_runed_item(equip_type, rune_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the rune type on equipped item for a given slot
|
||||
int get_equipped_rune_for_slot(int equip_type) {
|
||||
if (equip_type == EQUIP_SPEAR || equip_type == EQUIP_AXE ||
|
||||
@@ -148,6 +196,7 @@ void reset_rune_data() {
|
||||
rune_swiftness_unlocked = false;
|
||||
unicorn_boss_defeated = false;
|
||||
runed_items.delete_all();
|
||||
stored_runed_items.delete_all();
|
||||
equipped_head_rune = RUNE_NONE;
|
||||
equipped_torso_rune = RUNE_NONE;
|
||||
equipped_arms_rune = RUNE_NONE;
|
||||
|
||||
+80
-14
@@ -110,6 +110,7 @@ void stop_active_sounds() {
|
||||
p.destroy_sound(sling_sound_handle);
|
||||
sling_sound_handle = -1;
|
||||
}
|
||||
stop_all_weather_sounds();
|
||||
}
|
||||
|
||||
void clear_world_objects() {
|
||||
@@ -494,6 +495,36 @@ bool load_game_state_from_raw(const string&in rawData) {
|
||||
if (get_raw_number(rawData, "inventory_skin_tunics", value)) inv_skin_tunics = value;
|
||||
if (get_raw_number(rawData, "inventory_moccasins", value)) inv_moccasins = value;
|
||||
if (get_raw_number(rawData, "inventory_skin_pouches", value)) inv_skin_pouches = value;
|
||||
if (get_raw_number(rawData, "inventory_backpacks", value)) inv_backpacks = value;
|
||||
|
||||
if (get_raw_number(rawData, "storage_stones", value)) storage_stones = value;
|
||||
if (get_raw_number(rawData, "storage_sticks", value)) storage_sticks = value;
|
||||
if (get_raw_number(rawData, "storage_vines", value)) storage_vines = value;
|
||||
if (get_raw_number(rawData, "storage_reeds", value)) storage_reeds = value;
|
||||
if (get_raw_number(rawData, "storage_logs", value)) storage_logs = value;
|
||||
if (get_raw_number(rawData, "storage_clay", value)) storage_clay = value;
|
||||
if (get_raw_number(rawData, "storage_small_game", value)) storage_small_game = value;
|
||||
if (get_raw_number(rawData, "storage_meat", value)) storage_meat = value;
|
||||
if (get_raw_number(rawData, "storage_skins", value)) storage_skins = value;
|
||||
if (get_raw_number(rawData, "storage_feathers", value)) storage_feathers = value;
|
||||
if (get_raw_number(rawData, "storage_down", value)) storage_down = value;
|
||||
if (get_raw_number(rawData, "storage_incense", value)) storage_incense = value;
|
||||
if (get_raw_number(rawData, "storage_spears", value)) storage_spears = value;
|
||||
if (get_raw_number(rawData, "storage_snares", value)) storage_snares = value;
|
||||
if (get_raw_number(rawData, "storage_axes", value)) storage_axes = value;
|
||||
if (get_raw_number(rawData, "storage_knives", value)) storage_knives = value;
|
||||
if (get_raw_number(rawData, "storage_fishing_poles", value)) storage_fishing_poles = value;
|
||||
if (get_raw_number(rawData, "storage_slings", value)) storage_slings = value;
|
||||
if (get_raw_number(rawData, "storage_ropes", value)) storage_ropes = value;
|
||||
if (get_raw_number(rawData, "storage_reed_baskets", value)) storage_reed_baskets = value;
|
||||
if (get_raw_number(rawData, "storage_clay_pots", value)) storage_clay_pots = value;
|
||||
if (get_raw_number(rawData, "storage_skin_hats", value)) storage_skin_hats = value;
|
||||
if (get_raw_number(rawData, "storage_skin_gloves", value)) storage_skin_gloves = value;
|
||||
if (get_raw_number(rawData, "storage_skin_pants", value)) storage_skin_pants = value;
|
||||
if (get_raw_number(rawData, "storage_skin_tunics", value)) storage_skin_tunics = value;
|
||||
if (get_raw_number(rawData, "storage_moccasins", value)) storage_moccasins = value;
|
||||
if (get_raw_number(rawData, "storage_skin_pouches", value)) storage_skin_pouches = value;
|
||||
if (get_raw_number(rawData, "storage_backpacks", value)) storage_backpacks = value;
|
||||
|
||||
if (get_raw_bool(rawData, "equipment_spear_equipped", bool_value)) spear_equipped = bool_value;
|
||||
if (get_raw_bool(rawData, "equipment_axe_equipped", bool_value)) axe_equipped = bool_value;
|
||||
@@ -505,9 +536,12 @@ bool load_game_state_from_raw(const string&in rawData) {
|
||||
if (get_raw_number(rawData, "equipment_feet", value)) equipped_feet = value;
|
||||
if (get_raw_number(rawData, "equipment_arms", value)) equipped_arms = value;
|
||||
|
||||
if (equipped_arms != EQUIP_POUCH && equipped_arms != EQUIP_BACKPACK) equipped_arms = EQUIP_NONE;
|
||||
if (equipped_arms == EQUIP_POUCH && inv_skin_pouches <= 0) equipped_arms = EQUIP_NONE;
|
||||
if (equipped_arms == EQUIP_BACKPACK && inv_backpacks <= 0) equipped_arms = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_head)) equipped_head = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_torso)) equipped_torso = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_hands)) equipped_hands = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_legs)) equipped_legs = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_feet)) equipped_feet = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_arms)) equipped_arms = EQUIP_NONE;
|
||||
if (incense_hours_remaining > 0) incense_burning = true;
|
||||
|
||||
if (inv_small_game_types.length() == 0 && inv_small_game > 0) {
|
||||
@@ -642,6 +676,18 @@ bool save_game_state() {
|
||||
}
|
||||
saveData.set("runed_items", join_string_array(runed_items_data));
|
||||
|
||||
// Save stored runed items dictionary
|
||||
string[] stored_runed_items_data;
|
||||
string[]@ stored_keys = stored_runed_items.get_keys();
|
||||
for (uint i = 0; i < stored_keys.length(); i++) {
|
||||
string key = stored_keys[i];
|
||||
int count = int(stored_runed_items[key]);
|
||||
if (count > 0) {
|
||||
stored_runed_items_data.insert_last(key + "=" + count);
|
||||
}
|
||||
}
|
||||
saveData.set("stored_runed_items", join_string_array(stored_runed_items_data));
|
||||
|
||||
saveData.set("time_current_hour", current_hour);
|
||||
saveData.set("time_current_day", current_day);
|
||||
saveData.set("time_is_daytime", is_daytime);
|
||||
@@ -923,14 +969,9 @@ bool load_game_state() {
|
||||
equipped_hands = int(get_number(saveData, "equipment_hands", EQUIP_NONE));
|
||||
equipped_legs = int(get_number(saveData, "equipment_legs", EQUIP_NONE));
|
||||
equipped_feet = int(get_number(saveData, "equipment_feet", EQUIP_NONE));
|
||||
if (equipped_head != EQUIP_HAT) equipped_head = EQUIP_NONE;
|
||||
if (equipped_torso != EQUIP_TUNIC) equipped_torso = EQUIP_NONE;
|
||||
if (equipped_hands != EQUIP_GLOVES) equipped_hands = EQUIP_NONE;
|
||||
if (equipped_legs != EQUIP_PANTS) equipped_legs = EQUIP_NONE;
|
||||
if (equipped_feet != EQUIP_MOCCASINS) equipped_feet = EQUIP_NONE;
|
||||
if (equipped_arms != EQUIP_POUCH && equipped_arms != EQUIP_BACKPACK) equipped_arms = EQUIP_NONE;
|
||||
if (equipped_arms == EQUIP_POUCH && inv_skin_pouches <= 0) equipped_arms = EQUIP_NONE;
|
||||
if (equipped_arms == EQUIP_BACKPACK && inv_backpacks <= 0) equipped_arms = EQUIP_NONE;
|
||||
|
||||
// Note: Equipment validation moved after runed items are loaded (see below)
|
||||
|
||||
reset_quick_slots();
|
||||
string[] loadedQuickSlots = get_string_list_or_split(saveData, "equipment_quick_slots");
|
||||
uint slot_count = loadedQuickSlots.length();
|
||||
@@ -941,7 +982,6 @@ bool load_game_state() {
|
||||
quick_slots[i] = slot_value;
|
||||
}
|
||||
}
|
||||
update_max_health_from_equipment();
|
||||
|
||||
// Load rune system data
|
||||
rune_swiftness_unlocked = get_bool(saveData, "rune_swiftness_unlocked", false);
|
||||
@@ -969,6 +1009,32 @@ bool load_game_state() {
|
||||
}
|
||||
}
|
||||
|
||||
// Load stored runed items dictionary
|
||||
stored_runed_items.delete_all();
|
||||
string[] loaded_stored_runed_items = get_string_list_or_split(saveData, "stored_runed_items");
|
||||
for (uint i = 0; i < loaded_stored_runed_items.length(); i++) {
|
||||
string entry = loaded_stored_runed_items[i];
|
||||
int eq_pos = entry.find("=");
|
||||
if (eq_pos > 0) {
|
||||
string key = entry.substr(0, eq_pos);
|
||||
int count = parse_int(entry.substr(eq_pos + 1));
|
||||
if (count > 0) {
|
||||
stored_runed_items.set(key, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate equipped items now that runed items are loaded
|
||||
if (!equipment_available(equipped_head)) equipped_head = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_torso)) equipped_torso = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_hands)) equipped_hands = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_legs)) equipped_legs = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_feet)) equipped_feet = EQUIP_NONE;
|
||||
if (!equipment_available(equipped_arms)) equipped_arms = EQUIP_NONE;
|
||||
|
||||
// Now that both equipment and runes are loaded, update stats
|
||||
update_max_health_from_equipment();
|
||||
|
||||
current_hour = int(get_number(saveData, "time_current_hour", 8));
|
||||
current_day = int(get_number(saveData, "time_current_day", 1));
|
||||
sun_setting_warned = get_bool(saveData, "time_sun_setting_warned", false);
|
||||
@@ -1122,15 +1188,15 @@ bool load_game_state() {
|
||||
b.wander_direction_change_interval = random(BANDIT_WANDER_DIRECTION_CHANGE_MIN, BANDIT_WANDER_DIRECTION_CHANGE_MAX);
|
||||
b.wander_direction_timer.restart();
|
||||
b.move_timer.restart();
|
||||
b.alert_timer.restart();
|
||||
b.attack_timer.restart();
|
||||
|
||||
// Restore alert sound based on weapon type
|
||||
int sound_index = random(0, bandit_sounds.length() - 1);
|
||||
b.alert_sound = bandit_sounds[sound_index];
|
||||
b.next_alert_delay = random(BANDIT_ALERT_MIN_DELAY, BANDIT_ALERT_MAX_DELAY);
|
||||
|
||||
bandits.insert_last(b);
|
||||
// Start looping sound for loaded bandit
|
||||
b.sound_handle = play_1d_with_volume_step(b.alert_sound, x, b.position, true, BANDIT_SOUND_VOLUME_STEP);
|
||||
}
|
||||
|
||||
string[] mountainData = get_string_list_or_split(saveData, "mountains_data");
|
||||
|
||||
@@ -391,9 +391,9 @@ void update_time() {
|
||||
}
|
||||
|
||||
if (current_hour == 6) {
|
||||
save_game_state();
|
||||
process_daily_weapon_breakage();
|
||||
attempt_daily_quest();
|
||||
save_game_state();
|
||||
}
|
||||
attempt_daily_invasion();
|
||||
keep_base_fires_fed();
|
||||
|
||||
@@ -39,6 +39,13 @@ class ThunderStrike {
|
||||
movement_timer.restart();
|
||||
}
|
||||
|
||||
~ThunderStrike() {
|
||||
if (sound_handle != -1) {
|
||||
p.destroy_sound(sound_handle);
|
||||
sound_handle = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (direction == 0) return; // Stationary thunder
|
||||
|
||||
@@ -77,6 +84,7 @@ string[] thunder_sounds = {
|
||||
};
|
||||
|
||||
void init_weather() {
|
||||
stop_all_weather_sounds();
|
||||
weather_state = WEATHER_CLEAR;
|
||||
wind_intensity = INTENSITY_NONE;
|
||||
rain_intensity = INTENSITY_NONE;
|
||||
|
||||
Reference in New Issue
Block a user