Item breaking now happens for players too. Bandit adventured tweaked a bit. Rune of destruction added. Can be put anywhere only affective on weapons.
This commit is contained in:
Binary file not shown.
Binary file not shown.
+95
-25
@@ -202,17 +202,70 @@ const int RESIDENT_WEAPON_SPEAR = 0;
|
||||
const int RESIDENT_WEAPON_SLING = 1;
|
||||
const int RESIDENT_WEAPON_BOW = 2;
|
||||
|
||||
int get_stored_runed_weapon_count(int equipType) {
|
||||
int total = 0;
|
||||
int[] runeTypes;
|
||||
get_all_rune_types(runeTypes);
|
||||
for (uint i = 0; i < runeTypes.length(); i++) {
|
||||
total += get_stored_runed_item_count(equipType, runeTypes[i]);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
int get_total_stored_weapon_count(int equipType, int itemType) {
|
||||
return get_storage_count(itemType) + get_stored_runed_weapon_count(equipType);
|
||||
}
|
||||
|
||||
bool remove_random_stored_runed_weapon(int equipType) {
|
||||
int[] runeTypes;
|
||||
get_all_rune_types(runeTypes);
|
||||
int total = 0;
|
||||
for (uint i = 0; i < runeTypes.length(); i++) {
|
||||
total += get_stored_runed_item_count(equipType, runeTypes[i]);
|
||||
}
|
||||
if (total <= 0) return false;
|
||||
|
||||
int roll = random(1, total);
|
||||
int running = 0;
|
||||
for (uint i = 0; i < runeTypes.length(); i++) {
|
||||
int count = get_stored_runed_item_count(equipType, runeTypes[i]);
|
||||
if (count <= 0) continue;
|
||||
running += count;
|
||||
if (roll <= running) {
|
||||
remove_stored_runed_item(equipType, runeTypes[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool remove_random_stored_weapon(int equipType, int itemType) {
|
||||
int unrunedCount = get_storage_count(itemType);
|
||||
int runedCount = get_stored_runed_weapon_count(equipType);
|
||||
int total = unrunedCount + runedCount;
|
||||
if (total <= 0) return false;
|
||||
|
||||
int roll = random(1, total);
|
||||
if (roll <= unrunedCount) {
|
||||
if (unrunedCount > 0) add_storage_count(itemType, -1);
|
||||
return true;
|
||||
}
|
||||
return remove_random_stored_runed_weapon(equipType);
|
||||
}
|
||||
|
||||
int get_available_defense_weapons() {
|
||||
int count = get_storage_count(ITEM_SPEARS);
|
||||
int spearCount = get_total_stored_weapon_count(EQUIP_SPEAR, ITEM_SPEARS);
|
||||
int slingCount = 0;
|
||||
int bowCount = 0;
|
||||
// Slings only count if stones are available
|
||||
if (get_storage_count(ITEM_SLINGS) > 0 && get_storage_count(ITEM_STONES) > 0) {
|
||||
count += get_storage_count(ITEM_SLINGS);
|
||||
if (get_storage_count(ITEM_STONES) > 0) {
|
||||
slingCount = get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS);
|
||||
}
|
||||
// Bows only count if arrows are available
|
||||
if (get_storage_count(ITEM_BOWS) > 0 && get_storage_count(ITEM_ARROWS) > 0) {
|
||||
count += get_storage_count(ITEM_BOWS);
|
||||
if (get_storage_count(ITEM_ARROWS) > 0) {
|
||||
bowCount = get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS);
|
||||
}
|
||||
return count;
|
||||
return spearCount + slingCount + bowCount;
|
||||
}
|
||||
|
||||
bool can_residents_defend() {
|
||||
@@ -222,13 +275,15 @@ bool can_residents_defend() {
|
||||
|
||||
int choose_defense_weapon_type() {
|
||||
// Prefer bows if available
|
||||
int bowCount = (get_storage_count(ITEM_BOWS) > 0 && get_storage_count(ITEM_ARROWS) > 0)
|
||||
? get_storage_count(ITEM_BOWS)
|
||||
int bowCount = (get_storage_count(ITEM_ARROWS) > 0)
|
||||
? get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS)
|
||||
: 0;
|
||||
if (bowCount > 0) return RESIDENT_WEAPON_BOW;
|
||||
|
||||
int spearCount = get_storage_count(ITEM_SPEARS);
|
||||
int slingCount = (get_storage_count(ITEM_SLINGS) > 0 && get_storage_count(ITEM_STONES) > 0) ? get_storage_count(ITEM_SLINGS) : 0;
|
||||
int spearCount = get_total_stored_weapon_count(EQUIP_SPEAR, ITEM_SPEARS);
|
||||
int slingCount = (get_storage_count(ITEM_STONES) > 0)
|
||||
? get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS)
|
||||
: 0;
|
||||
int total = spearCount + slingCount;
|
||||
|
||||
if (total == 0) return RESIDENT_WEAPON_SPEAR;
|
||||
@@ -244,18 +299,25 @@ int perform_resident_defense() {
|
||||
|
||||
// Choose weapon type (bows preferred, otherwise weighted by availability)
|
||||
int weapon_type = choose_defense_weapon_type();
|
||||
int bowCount = (get_storage_count(ITEM_ARROWS) > 0)
|
||||
? get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS)
|
||||
: 0;
|
||||
int spearCount = get_total_stored_weapon_count(EQUIP_SPEAR, ITEM_SPEARS);
|
||||
int slingCount = (get_storage_count(ITEM_STONES) > 0)
|
||||
? get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS)
|
||||
: 0;
|
||||
|
||||
int damage = 0;
|
||||
if (weapon_type == RESIDENT_WEAPON_BOW && get_storage_count(ITEM_BOWS) > 0 && get_storage_count(ITEM_ARROWS) > 0) {
|
||||
if (weapon_type == RESIDENT_WEAPON_BOW && bowCount > 0) {
|
||||
damage = apply_resident_damage_bonus(random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX));
|
||||
add_storage_count(ITEM_ARROWS, -1);
|
||||
play_1d_with_volume_step("sounds/weapons/bow_fire.ogg", x, BASE_END + 1, false, RESIDENT_DEFENSE_VOLUME_STEP);
|
||||
} else if (weapon_type == RESIDENT_WEAPON_SPEAR && get_storage_count(ITEM_SPEARS) > 0) {
|
||||
} else if (weapon_type == RESIDENT_WEAPON_SPEAR && spearCount > 0) {
|
||||
damage = apply_resident_damage_bonus(RESIDENT_SPEAR_DAMAGE);
|
||||
// Weapons don't get consumed on use - they break via daily breakage check
|
||||
// Just play the sound
|
||||
play_1d_with_volume_step("sounds/weapons/spear_swing.ogg", x, BASE_END + 1, false, RESIDENT_DEFENSE_VOLUME_STEP);
|
||||
} else if (weapon_type == RESIDENT_WEAPON_SLING && get_storage_count(ITEM_SLINGS) > 0 && get_storage_count(ITEM_STONES) > 0) {
|
||||
} else if (weapon_type == RESIDENT_WEAPON_SLING && slingCount > 0) {
|
||||
damage = apply_resident_damage_bonus(random(RESIDENT_SLING_DAMAGE_MIN, RESIDENT_SLING_DAMAGE_MAX));
|
||||
// Slings use stones as ammo, so consume a stone
|
||||
add_storage_count(ITEM_STONES, -1);
|
||||
@@ -271,8 +333,10 @@ timer resident_ranged_timer;
|
||||
void attempt_resident_ranged_defense() {
|
||||
// Only if residents exist and have ranged weapons
|
||||
if (residents_count <= 0) return;
|
||||
bool has_bow = (get_storage_count(ITEM_BOWS) > 0 && get_storage_count(ITEM_ARROWS) > 0);
|
||||
bool has_sling = (get_storage_count(ITEM_SLINGS) > 0 && get_storage_count(ITEM_STONES) > 0);
|
||||
int bowCount = get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS);
|
||||
int slingCount = get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS);
|
||||
bool has_bow = (bowCount > 0 && get_storage_count(ITEM_ARROWS) > 0);
|
||||
bool has_sling = (slingCount > 0 && get_storage_count(ITEM_STONES) > 0);
|
||||
if (!has_bow && !has_sling) return;
|
||||
|
||||
// Cooldown between shots
|
||||
@@ -338,7 +402,10 @@ void attempt_resident_ranged_defense() {
|
||||
void process_daily_weapon_breakage() {
|
||||
if (residents_count <= 0) return;
|
||||
|
||||
int totalWeapons = get_storage_count(ITEM_SPEARS) + get_storage_count(ITEM_SLINGS) + get_storage_count(ITEM_BOWS);
|
||||
int spearTotal = get_total_stored_weapon_count(EQUIP_SPEAR, ITEM_SPEARS);
|
||||
int slingTotal = get_total_stored_weapon_count(EQUIP_SLING, ITEM_SLINGS);
|
||||
int bowTotal = get_total_stored_weapon_count(EQUIP_BOW, ITEM_BOWS);
|
||||
int totalWeapons = spearTotal + slingTotal + bowTotal;
|
||||
if (totalWeapons == 0) return;
|
||||
|
||||
// Number of breakage checks = min(residents, weapons)
|
||||
@@ -350,9 +417,9 @@ void process_daily_weapon_breakage() {
|
||||
int bowChecks = 0;
|
||||
|
||||
for (int i = 0; i < checksToPerform; i++) {
|
||||
int remainingSpears = get_storage_count(ITEM_SPEARS) - spearChecks;
|
||||
int remainingSlings = get_storage_count(ITEM_SLINGS) - slingChecks;
|
||||
int remainingBows = get_storage_count(ITEM_BOWS) - bowChecks;
|
||||
int remainingSpears = spearTotal - spearChecks;
|
||||
int remainingSlings = slingTotal - slingChecks;
|
||||
int remainingBows = bowTotal - bowChecks;
|
||||
int remaining = remainingSpears + remainingSlings + remainingBows;
|
||||
|
||||
if (remaining <= 0) break;
|
||||
@@ -393,8 +460,9 @@ void process_daily_weapon_breakage() {
|
||||
|
||||
// Apply breakage
|
||||
if (spearsBroken > 0) {
|
||||
add_storage_count(ITEM_SPEARS, -spearsBroken);
|
||||
if (get_storage_count(ITEM_SPEARS) < 0) set_storage_count(ITEM_SPEARS, 0);
|
||||
for (int i = 0; i < spearsBroken; i++) {
|
||||
remove_random_stored_weapon(EQUIP_SPEAR, ITEM_SPEARS);
|
||||
}
|
||||
string msg = (spearsBroken == 1)
|
||||
? "A resident's spear broke from wear."
|
||||
: spearsBroken + " spears broke from wear.";
|
||||
@@ -402,8 +470,9 @@ void process_daily_weapon_breakage() {
|
||||
}
|
||||
|
||||
if (slingsBroken > 0) {
|
||||
add_storage_count(ITEM_SLINGS, -slingsBroken);
|
||||
if (get_storage_count(ITEM_SLINGS) < 0) set_storage_count(ITEM_SLINGS, 0);
|
||||
for (int i = 0; i < slingsBroken; i++) {
|
||||
remove_random_stored_weapon(EQUIP_SLING, ITEM_SLINGS);
|
||||
}
|
||||
string msg = (slingsBroken == 1)
|
||||
? "A resident's sling broke from wear."
|
||||
: slingsBroken + " slings broke from wear.";
|
||||
@@ -411,8 +480,9 @@ void process_daily_weapon_breakage() {
|
||||
}
|
||||
|
||||
if (bowsBroken > 0) {
|
||||
add_storage_count(ITEM_BOWS, -bowsBroken);
|
||||
if (get_storage_count(ITEM_BOWS) < 0) set_storage_count(ITEM_BOWS, 0);
|
||||
for (int i = 0; i < bowsBroken; i++) {
|
||||
remove_random_stored_weapon(EQUIP_BOW, ITEM_BOWS);
|
||||
}
|
||||
string msg = (bowsBroken == 1)
|
||||
? "A resident's bow broke from wear."
|
||||
: bowsBroken + " bows broke from wear.";
|
||||
|
||||
@@ -89,6 +89,7 @@ void adventure_release_bow_attack(int player_x, int player_facing, AdventureRang
|
||||
}
|
||||
|
||||
int damage = get_bow_draw_damage(bow_draw_timer.elapsed);
|
||||
damage = apply_weapon_rune_damage(damage);
|
||||
add_personal_count(ITEM_ARROWS, -1);
|
||||
p.play_stationary("sounds/weapons/bow_fire.ogg", false);
|
||||
|
||||
@@ -130,6 +131,7 @@ void adventure_release_sling_attack(int player_x, int player_facing, AdventureRa
|
||||
int search_direction = (player_facing == 1) ? 1 : -1;
|
||||
int target_x = -1;
|
||||
int damage = random(SLING_DAMAGE_MIN, SLING_DAMAGE_MAX);
|
||||
damage = apply_weapon_rune_damage(damage);
|
||||
|
||||
if (@ranged_callback !is null) {
|
||||
target_x = ranged_callback(player_x, search_direction, SLING_RANGE, ADVENTURE_WEAPON_SLING, damage);
|
||||
|
||||
@@ -272,7 +272,7 @@ void run_bandit_hideout_adventure() {
|
||||
|
||||
if (hideoutBarricadeHealth <= 0) {
|
||||
cleanup_bandit_hideout_adventure();
|
||||
p.play_stationary("sounds/actions/break_snare.ogg", false);
|
||||
p.play_stationary("sounds/bosses/bandit/base_destroyed.ogg", false);
|
||||
give_bandit_hideout_rewards();
|
||||
return;
|
||||
}
|
||||
@@ -446,7 +446,8 @@ void play_hideout_melee_hit(int weaponType) {
|
||||
|
||||
bool hideout_melee_hit(int weaponType) {
|
||||
int range = (weaponType == ADVENTURE_WEAPON_SPEAR) ? 1 : 0;
|
||||
int damage = (weaponType == ADVENTURE_WEAPON_SPEAR) ? SPEAR_DAMAGE : AXE_DAMAGE;
|
||||
int baseDamage = (weaponType == ADVENTURE_WEAPON_SPEAR) ? SPEAR_DAMAGE : AXE_DAMAGE;
|
||||
int damage = apply_weapon_rune_damage(baseDamage);
|
||||
|
||||
for (int offset = -range; offset <= range; offset++) {
|
||||
int targetX = hideoutPlayerX + offset;
|
||||
@@ -653,7 +654,7 @@ void give_bandit_hideout_rewards() {
|
||||
rewards.insert_last("Storage rewards:");
|
||||
bool anyItems = false;
|
||||
for (int itemType = 0; itemType < ITEM_COUNT; itemType++) {
|
||||
int roll = random(0, 9);
|
||||
int roll = random(0, 5);
|
||||
if (roll <= 0) continue;
|
||||
int addedAmount = add_hideout_storage_item(itemType, roll);
|
||||
if (addedAmount <= 0) continue;
|
||||
@@ -665,5 +666,28 @@ void give_bandit_hideout_rewards() {
|
||||
}
|
||||
}
|
||||
|
||||
bool newRune = !rune_destruction_unlocked;
|
||||
rune_destruction_unlocked = true;
|
||||
rewards.insert_last("");
|
||||
if (newRune) {
|
||||
rewards.insert_last("Learned Rune of Destruction!");
|
||||
rewards.insert_last("You can now engrave weapons with this rune at the crafting menu.");
|
||||
} else {
|
||||
rewards.insert_last("You have already mastered the Rune of Destruction.");
|
||||
}
|
||||
|
||||
if (residents_count < MAX_RESIDENTS) {
|
||||
int survivorRoll = random(1, 100);
|
||||
if (survivorRoll <= 50) {
|
||||
residents_count += 1;
|
||||
if (residents_count > MAX_RESIDENTS) residents_count = MAX_RESIDENTS;
|
||||
rewards.insert_last("");
|
||||
rewards.insert_last("A survivor joins your base.");
|
||||
} else {
|
||||
rewards.insert_last("");
|
||||
rewards.insert_last("No survivors were found.");
|
||||
}
|
||||
}
|
||||
|
||||
text_reader_lines(rewards, "Bandit's Hideout", true);
|
||||
}
|
||||
|
||||
@@ -372,7 +372,8 @@ bool unicorn_melee_hit(int weapon_type) {
|
||||
|
||||
if (target_support != -1 && bridge_supports_health[target_support] > 0) {
|
||||
if (weapon_type == ADVENTURE_WEAPON_AXE) {
|
||||
bridge_supports_health[target_support] -= AXE_DAMAGE;
|
||||
int damage = apply_weapon_rune_damage(AXE_DAMAGE);
|
||||
bridge_supports_health[target_support] -= damage;
|
||||
if (bridge_supports_health[target_support] <= 0) {
|
||||
check_bridge_collapse();
|
||||
}
|
||||
@@ -381,7 +382,8 @@ bool unicorn_melee_hit(int weapon_type) {
|
||||
}
|
||||
|
||||
if (abs(player_arena_x - unicorn.x) <= 1) {
|
||||
int damage = (weapon_type == ADVENTURE_WEAPON_SPEAR) ? SPEAR_DAMAGE : AXE_DAMAGE;
|
||||
int baseDamage = (weapon_type == ADVENTURE_WEAPON_SPEAR) ? SPEAR_DAMAGE : AXE_DAMAGE;
|
||||
int damage = apply_weapon_rune_damage(baseDamage);
|
||||
apply_unicorn_damage(damage);
|
||||
return true;
|
||||
}
|
||||
|
||||
+7
-3
@@ -102,7 +102,8 @@ bool attack_enemy(int target_x, int damage) {
|
||||
void perform_spear_attack(int current_x) {
|
||||
p.play_stationary("sounds/weapons/spear_swing.ogg", false);
|
||||
|
||||
int hit_pos = attack_enemy_ranged(current_x - 1, current_x + 1, SPEAR_DAMAGE);
|
||||
int damage = apply_weapon_rune_damage(SPEAR_DAMAGE);
|
||||
int hit_pos = attack_enemy_ranged(current_x - 1, current_x + 1, damage);
|
||||
if (hit_pos != -1) {
|
||||
p.play_stationary("sounds/weapons/spear_hit.ogg", false);
|
||||
// Play hit sound based on enemy type (both use same hit sound for now)
|
||||
@@ -123,7 +124,8 @@ void perform_spear_attack(int current_x) {
|
||||
void perform_axe_attack(int current_x) {
|
||||
p.play_stationary("sounds/weapons/axe_swing.ogg", false);
|
||||
|
||||
if (attack_enemy(current_x, AXE_DAMAGE)) {
|
||||
int damage = apply_weapon_rune_damage(AXE_DAMAGE);
|
||||
if (attack_enemy(current_x, damage)) {
|
||||
p.play_stationary("sounds/weapons/axe_hit.ogg", false);
|
||||
// Play hit sound based on enemy type
|
||||
if (get_bandit_at(current_x) != null) {
|
||||
@@ -140,7 +142,7 @@ void perform_axe_attack(int current_x) {
|
||||
// Range: current_x (0 distance)
|
||||
// Damage: 4
|
||||
// Target: Trees
|
||||
damage_tree(current_x, 4);
|
||||
damage_tree(current_x, damage);
|
||||
}
|
||||
|
||||
void perform_sling_attack(int current_x) {
|
||||
@@ -273,6 +275,7 @@ void release_bow_attack(int player_x) {
|
||||
}
|
||||
|
||||
int damage = get_bow_draw_damage(bow_draw_timer.elapsed);
|
||||
damage = apply_weapon_rune_damage(damage);
|
||||
add_personal_count(ITEM_ARROWS, -1);
|
||||
p.play_stationary("sounds/weapons/bow_fire.ogg", false);
|
||||
|
||||
@@ -379,6 +382,7 @@ void release_sling_attack(int player_x) {
|
||||
}
|
||||
|
||||
int damage = random(SLING_DAMAGE_MIN, SLING_DAMAGE_MAX);
|
||||
damage = apply_weapon_rune_damage(damage);
|
||||
|
||||
// Damage the correct enemy type
|
||||
if (hit_bandit) {
|
||||
|
||||
@@ -204,6 +204,10 @@ const int RESIDENT_SNARE_CHECK_CHANCE = 15; // 15% chance per hour to check sna
|
||||
const int RESIDENT_FISHING_CHANCE = 6; // 6% chance per resident per hour to catch a fish
|
||||
const int RESIDENT_SMOKE_FISH_CHANCE = 10; // 10% chance per hour to smoke a stored fish
|
||||
const int RESIDENT_TOOL_BREAK_CHANCE = 2; // 2% chance tools break during resident use (fishing poles, knives, baskets)
|
||||
const int PLAYER_ITEM_BREAK_CHANCE_MIN = 1;
|
||||
const int PLAYER_ITEM_BREAK_CHANCE_MAX = 100;
|
||||
const int PLAYER_ITEM_BREAK_CHANCE_INCREMENT = 1;
|
||||
const int PLAYER_ITEM_BREAKS_PER_DAY = 2;
|
||||
|
||||
// Goose settings
|
||||
const int GOOSE_HEALTH = 1;
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
// Get total pouches available (unruned + runed)
|
||||
int get_total_pouch_count() {
|
||||
int total = get_personal_count(ITEM_SKIN_POUCHES);
|
||||
total += get_runed_item_count(EQUIP_POUCH, RUNE_SWIFTNESS);
|
||||
int[] runeTypes;
|
||||
get_all_rune_types(runeTypes);
|
||||
for (uint i = 0; i < runeTypes.length(); i++) {
|
||||
total += get_runed_item_count(EQUIP_POUCH, runeTypes[i]);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -21,10 +25,18 @@ void consume_pouches(int amount) {
|
||||
|
||||
// Then consume runed pouches if needed
|
||||
while (remaining > 0) {
|
||||
if (get_runed_item_count(EQUIP_POUCH, RUNE_SWIFTNESS) > 0) {
|
||||
remove_runed_item(EQUIP_POUCH, RUNE_SWIFTNESS);
|
||||
remaining--;
|
||||
} else {
|
||||
bool removed = false;
|
||||
int[] runeTypes;
|
||||
get_all_rune_types(runeTypes);
|
||||
for (uint i = 0; i < runeTypes.length(); i++) {
|
||||
if (get_runed_item_count(EQUIP_POUCH, runeTypes[i]) > 0) {
|
||||
remove_runed_item(EQUIP_POUCH, runeTypes[i]);
|
||||
remaining--;
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!removed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,10 +64,13 @@ void run_runes_menu() {
|
||||
// Build list of unlocked runes
|
||||
string[] rune_options;
|
||||
int[] rune_types;
|
||||
|
||||
if (rune_swiftness_unlocked) {
|
||||
rune_options.insert_last("Rune of Swiftness (1 Clay, 1 Favor) [Requires Knife]");
|
||||
rune_types.insert_last(RUNE_SWIFTNESS);
|
||||
int[] unlocked_runes;
|
||||
get_unlocked_rune_types(unlocked_runes);
|
||||
for (uint i = 0; i < unlocked_runes.length(); i++) {
|
||||
int rune_type = unlocked_runes[i];
|
||||
string label = get_rune_name(rune_type) + " (1 Clay, 1 Favor) [Requires Knife]";
|
||||
rune_options.insert_last(label);
|
||||
rune_types.insert_last(rune_type);
|
||||
}
|
||||
|
||||
if (rune_options.length() == 0) {
|
||||
@@ -112,7 +115,7 @@ void run_rune_equipment_menu(int rune_type) {
|
||||
string[] equipment_options;
|
||||
int[] equipment_types;
|
||||
|
||||
int[] runeable = get_runeable_equipment_types();
|
||||
int[] runeable = get_runeable_equipment_types_for_rune(rune_type);
|
||||
for (uint i = 0; i < runeable.length(); i++) {
|
||||
int equip_type = runeable[i];
|
||||
int unruned_count = get_unruned_equipment_count(equip_type);
|
||||
|
||||
@@ -261,6 +261,95 @@ string get_item_count_binding_name(int item_type) {
|
||||
return get_item_display_name(item_type);
|
||||
}
|
||||
|
||||
string get_runed_item_display_name(int equip_type, int rune_type) {
|
||||
return "Runed " + get_base_equipment_name(equip_type) + " of " + get_rune_effect_name(rune_type);
|
||||
}
|
||||
|
||||
string get_equipment_display_name_with_rune(int equip_type, int rune_type) {
|
||||
if (rune_type != RUNE_NONE) {
|
||||
return get_base_equipment_name(equip_type) + " of " + get_rune_effect_name(rune_type);
|
||||
}
|
||||
return get_equipment_name(equip_type);
|
||||
}
|
||||
|
||||
bool is_breakable_item_type(int itemType) {
|
||||
if (is_runed_item_type(itemType)) return true;
|
||||
if (itemType == ITEM_SPEARS) return true;
|
||||
if (itemType == ITEM_SLINGS) return true;
|
||||
if (itemType == ITEM_AXES) return true;
|
||||
if (itemType == ITEM_SNARES) return true;
|
||||
if (itemType == ITEM_KNIVES) return true;
|
||||
if (itemType == ITEM_FISHING_POLES) return true;
|
||||
if (itemType == ITEM_SKIN_HATS) return true;
|
||||
if (itemType == ITEM_SKIN_GLOVES) return true;
|
||||
if (itemType == ITEM_SKIN_PANTS) return true;
|
||||
if (itemType == ITEM_SKIN_TUNICS) return true;
|
||||
if (itemType == ITEM_MOCCASINS) return true;
|
||||
if (itemType == ITEM_SKIN_POUCHES) return true;
|
||||
if (itemType == ITEM_ROPES) return true;
|
||||
if (itemType == ITEM_REED_BASKETS) return true;
|
||||
if (itemType == ITEM_CLAY_POTS) return true;
|
||||
if (itemType == ITEM_BOWS) return true;
|
||||
if (itemType == ITEM_QUIVERS) return true;
|
||||
if (itemType == ITEM_BACKPACKS) return true;
|
||||
if (itemType == ITEM_CANOES) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
string get_breakable_item_name(int itemType) {
|
||||
if (is_runed_item_type(itemType)) {
|
||||
int equipType = 0;
|
||||
int runeType = 0;
|
||||
decode_runed_item_type(itemType, equipType, runeType);
|
||||
return "Runed " + get_base_equipment_name(equipType) + " of " + get_rune_effect_name(runeType);
|
||||
}
|
||||
return get_item_label_singular(itemType);
|
||||
}
|
||||
|
||||
void get_breakable_personal_item_types(int[]@ items) {
|
||||
if (@items == null) return;
|
||||
items.resize(0);
|
||||
for (int itemType = 0; itemType < ITEM_COUNT; itemType++) {
|
||||
if (!is_breakable_item_type(itemType)) continue;
|
||||
if (get_personal_count(itemType) <= 0) continue;
|
||||
items.insert_last(itemType);
|
||||
}
|
||||
|
||||
int[] runeable = get_runeable_equipment_types();
|
||||
for (uint i = 0; i < runeable.length(); i++) {
|
||||
int equipType = runeable[i];
|
||||
int[] runeTypes;
|
||||
get_all_rune_types(runeTypes);
|
||||
for (uint j = 0; j < runeTypes.length(); j++) {
|
||||
int runeType = runeTypes[j];
|
||||
int runedCount = get_runed_item_count(equipType, runeType);
|
||||
if (runedCount <= 0) continue;
|
||||
int encoded = encode_runed_item_type(equipType, runeType);
|
||||
items.insert_last(encoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool remove_breakable_personal_item(int itemType) {
|
||||
if (is_runed_item_type(itemType)) {
|
||||
int equipType = 0;
|
||||
int runeType = 0;
|
||||
decode_runed_item_type(itemType, equipType, runeType);
|
||||
int current = get_runed_item_count(equipType, runeType);
|
||||
if (current <= 0) return false;
|
||||
remove_runed_item(equipType, runeType);
|
||||
if (get_runed_item_count(equipType, runeType) <= 0 && get_equipped_rune_for_slot(equipType) == runeType) {
|
||||
clear_equipped_rune_for_slot(equipType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_breakable_item_type(itemType)) return false;
|
||||
if (get_personal_count(itemType) <= 0) return false;
|
||||
add_personal_count(itemType, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_consume_heal_scroll() {
|
||||
if (player_health > 0) return false;
|
||||
if (get_personal_count(ITEM_HEAL_SCROLL) <= 0) return false;
|
||||
@@ -304,13 +393,13 @@ void activate_quick_slot(int slot_index) {
|
||||
}
|
||||
set_equipped_rune_for_slot(equip_type, rune_type);
|
||||
update_max_health_from_equipment();
|
||||
speak_with_history(get_equipment_name(equip_type) + " equipped.", true);
|
||||
speak_with_history(get_equipment_display_name_with_rune(equip_type, rune_type) + " equipped.", true);
|
||||
return;
|
||||
}
|
||||
unequip_equipment_type(equip_type);
|
||||
clear_equipped_rune_for_slot(equip_type);
|
||||
update_max_health_from_equipment();
|
||||
speak_with_history(get_equipment_name(equip_type) + " unequipped.", true);
|
||||
speak_with_history(get_equipment_display_name_with_rune(equip_type, rune_type) + " unequipped.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -327,7 +416,7 @@ void activate_quick_slot(int slot_index) {
|
||||
equip_equipment_type(equip_type);
|
||||
set_equipped_rune_for_slot(equip_type, rune_type);
|
||||
update_max_health_from_equipment();
|
||||
speak_with_history(get_equipment_name(equip_type) + " equipped.", true);
|
||||
speak_with_history(get_equipment_display_name_with_rune(equip_type, rune_type) + " equipped.", true);
|
||||
}
|
||||
|
||||
void check_quick_slot_keys() {
|
||||
|
||||
@@ -16,9 +16,13 @@ bool has_any_equipment() {
|
||||
|
||||
// Check runed items
|
||||
int[] runeable = get_runeable_equipment_types();
|
||||
int[] rune_types;
|
||||
get_all_rune_types(rune_types);
|
||||
for (uint i = 0; i < runeable.length(); i++) {
|
||||
if (get_runed_item_count(runeable[i], RUNE_SWIFTNESS) > 0) {
|
||||
return true;
|
||||
for (uint j = 0; j < rune_types.length(); j++) {
|
||||
if (get_runed_item_count(runeable[i], rune_types[j]) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +43,7 @@ void check_equipment_menu() {
|
||||
string get_full_equipment_name(int equip_type, int rune_type) {
|
||||
string base_name = get_base_equipment_name(equip_type);
|
||||
if (rune_type != RUNE_NONE) {
|
||||
return "Runed " + base_name + " of " + get_rune_effect_name(rune_type);
|
||||
return get_runed_item_display_name(equip_type, rune_type);
|
||||
}
|
||||
return base_name;
|
||||
}
|
||||
@@ -132,17 +136,21 @@ void run_equipment_menu() {
|
||||
rune_types.insert_last(RUNE_NONE);
|
||||
}
|
||||
|
||||
// Add runed items (currently only swiftness rune)
|
||||
// Add runed items
|
||||
int[] runeable = get_runeable_equipment_types();
|
||||
int[] all_rune_types;
|
||||
get_all_rune_types(all_rune_types);
|
||||
for (uint i = 0; i < runeable.length(); i++) {
|
||||
int equip_type = runeable[i];
|
||||
int count = get_runed_item_count(equip_type, RUNE_SWIFTNESS);
|
||||
if (count > 0) {
|
||||
string name = get_full_equipment_name(equip_type, RUNE_SWIFTNESS);
|
||||
string status = is_runed_item_equipped(equip_type, RUNE_SWIFTNESS) ? " (equipped)" : "";
|
||||
for (uint j = 0; j < all_rune_types.length(); j++) {
|
||||
int rune_type = all_rune_types[j];
|
||||
int count = get_runed_item_count(equip_type, rune_type);
|
||||
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)" : "";
|
||||
options.insert_last(name + status);
|
||||
equipment_types.insert_last(equip_type);
|
||||
rune_types.insert_last(RUNE_SWIFTNESS);
|
||||
rune_types.insert_last(rune_type);
|
||||
}
|
||||
}
|
||||
string filter_text = "";
|
||||
|
||||
@@ -16,13 +16,17 @@ void build_personal_inventory_options(string[]@ options, int[]@ item_types) {
|
||||
|
||||
// Add runed items
|
||||
int[] runeable = get_runeable_equipment_types();
|
||||
int[] rune_types;
|
||||
get_all_rune_types(rune_types);
|
||||
for (uint i = 0; i < runeable.length(); i++) {
|
||||
int equip_type = runeable[i];
|
||||
int count = get_runed_item_count(equip_type, RUNE_SWIFTNESS);
|
||||
if (count > 0) {
|
||||
string name = "Runed " + get_base_equipment_name(equip_type) + " of Quickness";
|
||||
for (uint j = 0; j < rune_types.length(); j++) {
|
||||
int rune_type = rune_types[j];
|
||||
int count = get_runed_item_count(equip_type, rune_type);
|
||||
if (count <= 0) continue;
|
||||
string name = get_runed_item_display_name(equip_type, rune_type);
|
||||
options.insert_last(name + ": " + count);
|
||||
item_types.insert_last(encode_runed_item_type(equip_type, RUNE_SWIFTNESS));
|
||||
item_types.insert_last(encode_runed_item_type(equip_type, rune_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,11 +53,16 @@ void show_inventory() {
|
||||
// Add runed items summary
|
||||
string runed_info = "";
|
||||
int[] runeable = get_runeable_equipment_types();
|
||||
int[] rune_types;
|
||||
get_all_rune_types(rune_types);
|
||||
for (uint i = 0; i < runeable.length(); i++) {
|
||||
int count = get_runed_item_count(runeable[i], RUNE_SWIFTNESS);
|
||||
if (count > 0) {
|
||||
int equip_type = runeable[i];
|
||||
for (uint j = 0; j < rune_types.length(); j++) {
|
||||
int rune_type = rune_types[j];
|
||||
int count = get_runed_item_count(equip_type, rune_type);
|
||||
if (count <= 0) continue;
|
||||
if (runed_info.length() > 0) runed_info += ", ";
|
||||
runed_info += count + " Runed " + get_base_equipment_name(runeable[i]) + " of Quickness";
|
||||
runed_info += count + " " + get_runed_item_display_name(equip_type, rune_type);
|
||||
}
|
||||
}
|
||||
if (runed_info.length() > 0) {
|
||||
|
||||
@@ -271,13 +271,17 @@ void build_storage_inventory_options(string[]@ options, int[]@ item_types) {
|
||||
|
||||
// Add stored runed items
|
||||
int[] runeable = get_runeable_equipment_types();
|
||||
int[] rune_types;
|
||||
get_all_rune_types(rune_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";
|
||||
for (uint j = 0; j < rune_types.length(); j++) {
|
||||
int rune_type = rune_types[j];
|
||||
int count = get_stored_runed_item_count(equip_type, rune_type);
|
||||
if (count <= 0) continue;
|
||||
string name = get_runed_item_display_name(equip_type, rune_type);
|
||||
options.insert_last(name + ": " + count);
|
||||
item_types.insert_last(encode_runed_item_type(equip_type, RUNE_SWIFTNESS));
|
||||
item_types.insert_last(encode_runed_item_type(equip_type, rune_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
// Rune type constants
|
||||
const int RUNE_NONE = -1;
|
||||
const int RUNE_SWIFTNESS = 0;
|
||||
const int RUNE_DESTRUCTION = 1;
|
||||
|
||||
// Rune unlock tracking (persisted in save)
|
||||
bool rune_swiftness_unlocked = false;
|
||||
bool rune_destruction_unlocked = false;
|
||||
|
||||
// Boss defeat tracking
|
||||
bool unicorn_boss_defeated = false;
|
||||
@@ -37,26 +39,43 @@ int equipped_weapon_rune = RUNE_NONE;
|
||||
// Get display name for a rune type
|
||||
string get_rune_name(int rune_type) {
|
||||
if (rune_type == RUNE_SWIFTNESS) return "Rune of Swiftness";
|
||||
if (rune_type == RUNE_DESTRUCTION) return "Rune of Destruction";
|
||||
return "Unknown Rune";
|
||||
}
|
||||
|
||||
// Get the effect suffix for runed item names (e.g., "of Quickness")
|
||||
string get_rune_effect_name(int rune_type) {
|
||||
if (rune_type == RUNE_SWIFTNESS) return "Quickness";
|
||||
if (rune_type == RUNE_DESTRUCTION) return "Destruction";
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
// Check if any rune has been unlocked
|
||||
bool any_rune_unlocked() {
|
||||
return rune_swiftness_unlocked;
|
||||
return rune_swiftness_unlocked || rune_destruction_unlocked;
|
||||
}
|
||||
|
||||
// Check if a specific rune is unlocked
|
||||
bool is_rune_unlocked(int rune_type) {
|
||||
if (rune_type == RUNE_SWIFTNESS) return rune_swiftness_unlocked;
|
||||
if (rune_type == RUNE_DESTRUCTION) return rune_destruction_unlocked;
|
||||
return false;
|
||||
}
|
||||
|
||||
void get_all_rune_types(int[]@ runeTypes) {
|
||||
if (@runeTypes == null) return;
|
||||
runeTypes.resize(0);
|
||||
runeTypes.insert_last(RUNE_SWIFTNESS);
|
||||
runeTypes.insert_last(RUNE_DESTRUCTION);
|
||||
}
|
||||
|
||||
void get_unlocked_rune_types(int[]@ runeTypes) {
|
||||
if (@runeTypes == null) return;
|
||||
runeTypes.resize(0);
|
||||
if (rune_swiftness_unlocked) runeTypes.insert_last(RUNE_SWIFTNESS);
|
||||
if (rune_destruction_unlocked) runeTypes.insert_last(RUNE_DESTRUCTION);
|
||||
}
|
||||
|
||||
// Create dictionary key for runed item storage
|
||||
string make_runed_key(int equip_type, int rune_type) {
|
||||
return "" + equip_type + ":" + rune_type;
|
||||
@@ -89,8 +108,11 @@ void remove_runed_item(int equip_type, int rune_type) {
|
||||
|
||||
// Check if player has any runed version of an equipment type
|
||||
bool has_any_runed_version(int equip_type) {
|
||||
// Check all rune types
|
||||
if (get_runed_item_count(equip_type, RUNE_SWIFTNESS) > 0) return true;
|
||||
int[] runeTypes;
|
||||
get_all_rune_types(runeTypes);
|
||||
for (uint i = 0; i < runeTypes.length(); i++) {
|
||||
if (get_runed_item_count(equip_type, runeTypes[i]) > 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -191,9 +213,22 @@ int[] get_runeable_equipment_types() {
|
||||
return types;
|
||||
}
|
||||
|
||||
int[] get_runeable_equipment_types_for_rune(int rune_type) {
|
||||
if (rune_type == RUNE_DESTRUCTION) {
|
||||
int[] types;
|
||||
types.insert_last(EQUIP_SPEAR);
|
||||
types.insert_last(EQUIP_AXE);
|
||||
types.insert_last(EQUIP_SLING);
|
||||
types.insert_last(EQUIP_BOW);
|
||||
return types;
|
||||
}
|
||||
return get_runeable_equipment_types();
|
||||
}
|
||||
|
||||
// Reset all rune data for new game
|
||||
void reset_rune_data() {
|
||||
rune_swiftness_unlocked = false;
|
||||
rune_destruction_unlocked = false;
|
||||
unicorn_boss_defeated = false;
|
||||
runed_items.delete_all();
|
||||
stored_runed_items.delete_all();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Rune Effects - Calculate bonuses from equipped runed items
|
||||
// This file handles the actual gameplay effects of runes
|
||||
|
||||
const int RUNE_DESTRUCTION_DAMAGE_MULTIPLIER = 2;
|
||||
|
||||
// Calculate total walking speed bonus from all equipped runed items
|
||||
int get_total_rune_walk_speed_bonus() {
|
||||
int bonus = 0;
|
||||
@@ -79,3 +81,11 @@ string get_rune_speed_description() {
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
int apply_weapon_rune_damage(int baseDamage) {
|
||||
if (baseDamage <= 0) return baseDamage;
|
||||
if (equipped_weapon_rune == RUNE_DESTRUCTION) {
|
||||
return baseDamage * RUNE_DESTRUCTION_DAMAGE_MULTIPLIER;
|
||||
}
|
||||
return baseDamage;
|
||||
}
|
||||
|
||||
@@ -625,6 +625,13 @@ void reset_game_state() {
|
||||
invasion_scheduled_hour = -1;
|
||||
quest_roll_done_today = false;
|
||||
quest_queue.resize(0);
|
||||
playerItemBreakChance = PLAYER_ITEM_BREAK_CHANCE_MIN;
|
||||
playerItemBreaksToday = 0;
|
||||
playerItemBreakPending = false;
|
||||
playerItemBreakPendingType = -1;
|
||||
playerItemBreakMessage = "";
|
||||
playerItemBreakSoundHandle = -1;
|
||||
playerItemBreakSoundPending = false;
|
||||
|
||||
walktimer.restart();
|
||||
jumptimer.restart();
|
||||
@@ -823,6 +830,7 @@ bool save_game_state() {
|
||||
|
||||
// Rune system data
|
||||
saveData.set("rune_swiftness_unlocked", rune_swiftness_unlocked);
|
||||
saveData.set("rune_destruction_unlocked", rune_destruction_unlocked);
|
||||
saveData.set("unicorn_boss_defeated", unicorn_boss_defeated);
|
||||
saveData.set("equipped_head_rune", equipped_head_rune);
|
||||
saveData.set("equipped_torso_rune", equipped_torso_rune);
|
||||
@@ -869,6 +877,10 @@ bool save_game_state() {
|
||||
saveData.set("time_invasion_roll_done_today", invasion_roll_done_today);
|
||||
saveData.set("time_invasion_scheduled_hour", invasion_scheduled_hour);
|
||||
saveData.set("time_invasion_enemy_type", invasion_enemy_type);
|
||||
saveData.set("player_item_break_chance", playerItemBreakChance);
|
||||
saveData.set("player_item_breaks_today", playerItemBreaksToday);
|
||||
saveData.set("player_item_break_pending", playerItemBreakPending);
|
||||
saveData.set("player_item_break_pending_type", playerItemBreakPendingType);
|
||||
saveData.set("quest_roll_done_today", quest_roll_done_today);
|
||||
saveData.set("wight_spawn_chance", wight_spawn_chance);
|
||||
saveData.set("wight_spawned_this_night", wight_spawned_this_night);
|
||||
@@ -1186,6 +1198,7 @@ bool load_game_state_from_file(const string&in filename) {
|
||||
|
||||
// Load rune system data
|
||||
rune_swiftness_unlocked = get_bool(saveData, "rune_swiftness_unlocked", false);
|
||||
rune_destruction_unlocked = get_bool(saveData, "rune_destruction_unlocked", false);
|
||||
unicorn_boss_defeated = get_bool(saveData, "unicorn_boss_defeated", false);
|
||||
equipped_head_rune = int(get_number(saveData, "equipped_head_rune", RUNE_NONE));
|
||||
equipped_torso_rune = int(get_number(saveData, "equipped_torso_rune", RUNE_NONE));
|
||||
@@ -1287,6 +1300,31 @@ bool load_game_state_from_file(const string&in filename) {
|
||||
if (invasion_chance > 100) invasion_chance = 100;
|
||||
if (invasion_scheduled_hour < -1) invasion_scheduled_hour = -1;
|
||||
if (invasion_scheduled_hour > 23) invasion_scheduled_hour = -1;
|
||||
playerItemBreakChance = int(get_number(saveData, "player_item_break_chance", PLAYER_ITEM_BREAK_CHANCE_MIN));
|
||||
playerItemBreaksToday = int(get_number(saveData, "player_item_breaks_today", 0));
|
||||
playerItemBreakPending = get_bool(saveData, "player_item_break_pending", false);
|
||||
playerItemBreakPendingType = int(get_number(saveData, "player_item_break_pending_type", -1));
|
||||
if (playerItemBreakChance < PLAYER_ITEM_BREAK_CHANCE_MIN) {
|
||||
playerItemBreakChance = PLAYER_ITEM_BREAK_CHANCE_MIN;
|
||||
}
|
||||
if (playerItemBreakChance > PLAYER_ITEM_BREAK_CHANCE_MAX) {
|
||||
playerItemBreakChance = PLAYER_ITEM_BREAK_CHANCE_MAX;
|
||||
}
|
||||
if (playerItemBreaksToday < 0) playerItemBreaksToday = 0;
|
||||
if (playerItemBreaksToday > PLAYER_ITEM_BREAKS_PER_DAY) {
|
||||
playerItemBreaksToday = PLAYER_ITEM_BREAKS_PER_DAY;
|
||||
}
|
||||
if (playerItemBreakPending) {
|
||||
bool validPending = (playerItemBreakPendingType >= 0 && playerItemBreakPendingType < ITEM_COUNT)
|
||||
|| is_runed_item_type(playerItemBreakPendingType);
|
||||
if (!validPending) {
|
||||
playerItemBreakPending = false;
|
||||
playerItemBreakPendingType = -1;
|
||||
}
|
||||
} else {
|
||||
playerItemBreakPendingType = -1;
|
||||
}
|
||||
reset_player_item_break_audio_state();
|
||||
quest_roll_done_today = get_bool(saveData, "quest_roll_done_today", false);
|
||||
wight_spawn_chance = int(get_number(saveData, "wight_spawn_chance", WIGHT_SPAWN_CHANCE_START));
|
||||
wight_spawned_this_night = get_bool(saveData, "wight_spawned_this_night", false);
|
||||
|
||||
@@ -12,6 +12,14 @@ bool is_daytime = true;
|
||||
bool sun_setting_warned = false;
|
||||
bool sunrise_warned = false;
|
||||
|
||||
int playerItemBreakChance = PLAYER_ITEM_BREAK_CHANCE_MIN;
|
||||
int playerItemBreaksToday = 0;
|
||||
bool playerItemBreakPending = false;
|
||||
int playerItemBreakPendingType = -1;
|
||||
string playerItemBreakMessage = "";
|
||||
int playerItemBreakSoundHandle = -1;
|
||||
bool playerItemBreakSoundPending = false;
|
||||
|
||||
// Crossfade state
|
||||
bool crossfade_active = false;
|
||||
bool crossfade_to_night = false; // true = fading to night, false = fading to day
|
||||
@@ -53,9 +61,95 @@ void init_time() {
|
||||
invasion_roll_done_today = false;
|
||||
invasion_scheduled_hour = -1;
|
||||
invasion_enemy_type = "bandit";
|
||||
reset_player_item_break_state();
|
||||
update_ambience(true); // Force start
|
||||
}
|
||||
|
||||
void reset_player_item_break_audio_state() {
|
||||
playerItemBreakMessage = "";
|
||||
playerItemBreakSoundHandle = -1;
|
||||
playerItemBreakSoundPending = false;
|
||||
}
|
||||
|
||||
void reset_player_item_break_state() {
|
||||
playerItemBreakChance = PLAYER_ITEM_BREAK_CHANCE_MIN;
|
||||
playerItemBreaksToday = 0;
|
||||
playerItemBreakPending = false;
|
||||
playerItemBreakPendingType = -1;
|
||||
reset_player_item_break_audio_state();
|
||||
}
|
||||
|
||||
void queue_player_item_break_message(const string&in message) {
|
||||
if (message.length() == 0) return;
|
||||
playerItemBreakMessage = message;
|
||||
playerItemBreakSoundHandle = p.play_stationary("sounds/items/item_breaks.ogg", false);
|
||||
playerItemBreakSoundPending = true;
|
||||
}
|
||||
|
||||
void update_player_item_break_message() {
|
||||
if (!playerItemBreakSoundPending) return;
|
||||
if (playerItemBreakSoundHandle != -1 && p.sound_is_active(playerItemBreakSoundHandle)) {
|
||||
return;
|
||||
}
|
||||
playerItemBreakSoundHandle = -1;
|
||||
playerItemBreakSoundPending = false;
|
||||
if (playerItemBreakMessage.length() > 0) {
|
||||
speak_with_history(playerItemBreakMessage, true);
|
||||
playerItemBreakMessage = "";
|
||||
}
|
||||
}
|
||||
|
||||
void resolve_pending_player_item_break() {
|
||||
if (!playerItemBreakPending) return;
|
||||
if (x > BASE_END) return;
|
||||
if (playerItemBreakPendingType == -1) {
|
||||
playerItemBreakPending = false;
|
||||
return;
|
||||
}
|
||||
if (remove_breakable_personal_item(playerItemBreakPendingType)) {
|
||||
cleanup_equipment_after_inventory_change();
|
||||
string itemName = get_breakable_item_name(playerItemBreakPendingType);
|
||||
queue_player_item_break_message(itemName + " is worn out so you discard it.");
|
||||
}
|
||||
playerItemBreakPending = false;
|
||||
playerItemBreakPendingType = -1;
|
||||
}
|
||||
|
||||
void attempt_player_item_break_check() {
|
||||
if (playerItemBreakPending) return;
|
||||
if (playerItemBreaksToday >= PLAYER_ITEM_BREAKS_PER_DAY) return;
|
||||
|
||||
int[] breakableItems;
|
||||
get_breakable_personal_item_types(breakableItems);
|
||||
if (breakableItems.length() == 0) return;
|
||||
|
||||
int roll = random(1, 100);
|
||||
if (roll <= playerItemBreakChance) {
|
||||
int pickIndex = random(0, int(breakableItems.length()) - 1);
|
||||
int itemType = breakableItems[pickIndex];
|
||||
playerItemBreakChance = PLAYER_ITEM_BREAK_CHANCE_MIN;
|
||||
playerItemBreaksToday++;
|
||||
|
||||
if (x <= BASE_END) {
|
||||
if (remove_breakable_personal_item(itemType)) {
|
||||
cleanup_equipment_after_inventory_change();
|
||||
string itemName = get_breakable_item_name(itemType);
|
||||
queue_player_item_break_message(itemName + " is worn out so you discard it.");
|
||||
}
|
||||
} else {
|
||||
playerItemBreakPending = true;
|
||||
playerItemBreakPendingType = itemType;
|
||||
}
|
||||
} else {
|
||||
if (playerItemBreakChance < PLAYER_ITEM_BREAK_CHANCE_MAX) {
|
||||
playerItemBreakChance += PLAYER_ITEM_BREAK_CHANCE_INCREMENT;
|
||||
}
|
||||
if (playerItemBreakChance > PLAYER_ITEM_BREAK_CHANCE_MAX) {
|
||||
playerItemBreakChance = PLAYER_ITEM_BREAK_CHANCE_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string get_invasion_enemy_type_for_terrain(const string&in terrain_type) {
|
||||
for (uint i = 0; i < invasion_terrain_enemy_map.length(); i++) {
|
||||
string entry = invasion_terrain_enemy_map[i];
|
||||
@@ -452,6 +546,9 @@ bool should_attempt_resident_foraging(int hour) {
|
||||
}
|
||||
|
||||
void update_time() {
|
||||
update_player_item_break_message();
|
||||
resolve_pending_player_item_break();
|
||||
|
||||
if (hour_timer.elapsed >= MS_PER_HOUR) {
|
||||
hour_timer.restart();
|
||||
current_hour++;
|
||||
@@ -464,6 +561,7 @@ void update_time() {
|
||||
invasion_roll_done_today = false;
|
||||
invasion_scheduled_hour = -1;
|
||||
quest_roll_done_today = false;
|
||||
playerItemBreaksToday = 0;
|
||||
}
|
||||
|
||||
// Residents consume food every 8 hours (at midnight, 8am, 4pm)
|
||||
@@ -530,6 +628,7 @@ void update_time() {
|
||||
}
|
||||
attempt_daily_invasion();
|
||||
keep_base_fires_fed();
|
||||
attempt_player_item_break_check();
|
||||
update_incense_burning();
|
||||
attempt_hourly_flying_creature_spawn();
|
||||
attempt_hourly_boar_spawn();
|
||||
|
||||
Reference in New Issue
Block a user