A ton of changes including bug fixes, new craftable items, altar with favor system added. Info for player and base added.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
const string SAVE_FILE_PATH = "save.dat";
|
||||
const string SAVE_ENCRYPTION_KEY = "draugnorak_save_v1";
|
||||
const int SAVE_VERSION = 1;
|
||||
string last_save_error = "";
|
||||
|
||||
bool has_save_game() {
|
||||
return file_exists(SAVE_FILE_PATH);
|
||||
@@ -47,15 +48,42 @@ bool read_file_string(const string&in filename, string&out data) {
|
||||
double get_number(dictionary@ data, const string&in key, double defaultValue) {
|
||||
double value;
|
||||
if (@data == null) return defaultValue;
|
||||
if (!data.get(key, value)) return defaultValue;
|
||||
return value;
|
||||
if (data.get(key, value)) return value;
|
||||
int value_int;
|
||||
if (data.get(key, value_int)) return value_int;
|
||||
string value_str;
|
||||
if (data.get(key, value_str)) {
|
||||
return parse_int(value_str);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
bool get_bool(dictionary@ data, const string&in key, bool defaultValue) {
|
||||
bool value;
|
||||
if (@data == null) return defaultValue;
|
||||
if (!data.get(key, value)) return defaultValue;
|
||||
return value;
|
||||
if (data.get(key, value)) return value;
|
||||
int value_int;
|
||||
if (data.get(key, value_int)) return value_int != 0;
|
||||
string value_str;
|
||||
if (data.get(key, value_str)) return value_str == "1" || value_str == "true";
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
bool dictionary_has_keys(dictionary@ data) {
|
||||
if (@data == null) return false;
|
||||
string[]@ keys = data.get_keys();
|
||||
return keys.length() > 0;
|
||||
}
|
||||
|
||||
bool has_number_key(dictionary@ data, const string&in key) {
|
||||
double value;
|
||||
if (@data == null) return false;
|
||||
if (data.get(key, value)) return true;
|
||||
int value_int;
|
||||
if (data.get(key, value_int)) return true;
|
||||
string value_str;
|
||||
if (data.get(key, value_str)) return value_str.length() > 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] get_string_list(dictionary@ data, const string&in key) {
|
||||
@@ -102,6 +130,10 @@ void clear_world_objects() {
|
||||
|
||||
world_firepits.resize(0);
|
||||
world_herb_gardens.resize(0);
|
||||
world_storages.resize(0);
|
||||
world_pastures.resize(0);
|
||||
world_stables.resize(0);
|
||||
world_altars.resize(0);
|
||||
|
||||
for (uint i = 0; i < trees.length(); i++) {
|
||||
if (trees[i].sound_handle != -1) {
|
||||
@@ -131,11 +163,15 @@ void reset_game_state() {
|
||||
searching = false;
|
||||
|
||||
player_health = 10;
|
||||
base_max_health = 10;
|
||||
max_health = 10;
|
||||
favor = 0.0;
|
||||
blessing_speed_active = false;
|
||||
|
||||
inv_stones = 0;
|
||||
inv_sticks = 0;
|
||||
inv_vines = 0;
|
||||
inv_reeds = 0;
|
||||
inv_logs = 0;
|
||||
inv_clay = 0;
|
||||
inv_small_game = 0;
|
||||
@@ -148,10 +184,52 @@ void reset_game_state() {
|
||||
inv_knives = 0;
|
||||
inv_fishing_poles = 0;
|
||||
inv_slings = 0;
|
||||
inv_ropes = 0;
|
||||
inv_reed_baskets = 0;
|
||||
inv_clay_pots = 0;
|
||||
inv_skin_hats = 0;
|
||||
inv_skin_gloves = 0;
|
||||
inv_skin_pants = 0;
|
||||
inv_skin_tunics = 0;
|
||||
inv_moccasins = 0;
|
||||
inv_skin_pouches = 0;
|
||||
storage_stones = 0;
|
||||
storage_sticks = 0;
|
||||
storage_vines = 0;
|
||||
storage_reeds = 0;
|
||||
storage_logs = 0;
|
||||
storage_clay = 0;
|
||||
storage_small_game = 0;
|
||||
storage_small_game_types.resize(0);
|
||||
storage_meat = 0;
|
||||
storage_skins = 0;
|
||||
storage_spears = 0;
|
||||
storage_snares = 0;
|
||||
storage_axes = 0;
|
||||
storage_knives = 0;
|
||||
storage_fishing_poles = 0;
|
||||
storage_slings = 0;
|
||||
storage_ropes = 0;
|
||||
storage_reed_baskets = 0;
|
||||
storage_clay_pots = 0;
|
||||
storage_skin_hats = 0;
|
||||
storage_skin_gloves = 0;
|
||||
storage_skin_pants = 0;
|
||||
storage_skin_tunics = 0;
|
||||
storage_moccasins = 0;
|
||||
storage_skin_pouches = 0;
|
||||
|
||||
spear_equipped = false;
|
||||
axe_equipped = false;
|
||||
sling_equipped = false;
|
||||
equipped_head = EQUIP_NONE;
|
||||
equipped_torso = EQUIP_NONE;
|
||||
equipped_arms = EQUIP_NONE;
|
||||
equipped_hands = EQUIP_NONE;
|
||||
equipped_legs = EQUIP_NONE;
|
||||
equipped_feet = EQUIP_NONE;
|
||||
reset_quick_slots();
|
||||
update_max_health_from_equipment();
|
||||
|
||||
MAP_SIZE = 35;
|
||||
expanded_area_start = -1;
|
||||
@@ -160,15 +238,24 @@ void reset_game_state() {
|
||||
|
||||
barricade_health = 0;
|
||||
barricade_initialized = false;
|
||||
residents_count = 0;
|
||||
|
||||
current_hour = 8;
|
||||
current_day = 1;
|
||||
is_daytime = true;
|
||||
sun_setting_warned = false;
|
||||
sunrise_warned = false;
|
||||
crossfade_active = false;
|
||||
crossfade_to_night = false;
|
||||
area_expanded_today = false;
|
||||
invasion_active = false;
|
||||
invasion_start_hour = -1;
|
||||
invasion_chance = 25;
|
||||
invasion_triggered_today = false;
|
||||
invasion_roll_done_today = false;
|
||||
invasion_scheduled_hour = -1;
|
||||
quest_roll_done_today = false;
|
||||
quest_queue.resize(0);
|
||||
|
||||
walktimer.restart();
|
||||
jumptimer.restart();
|
||||
@@ -188,6 +275,7 @@ void start_new_game() {
|
||||
spawn_trees(5, 19);
|
||||
init_barricade();
|
||||
init_time();
|
||||
save_game_state();
|
||||
}
|
||||
|
||||
string serialize_bool(bool value) {
|
||||
@@ -210,6 +298,181 @@ string serialize_stream(WorldStream@ stream) {
|
||||
return stream.start_position + "|" + stream.get_width();
|
||||
}
|
||||
|
||||
string serialize_bandit(Bandit@ bandit) {
|
||||
return bandit.position + "|" + bandit.health + "|" + bandit.weapon_type + "|" + bandit.behavior_state + "|" + bandit.wander_direction + "|" + bandit.move_interval;
|
||||
}
|
||||
|
||||
string join_string_array(const string[]@ arr) {
|
||||
if (@arr == null || arr.length() == 0) return "";
|
||||
string result = arr[0];
|
||||
for (uint i = 1; i < arr.length(); i++) {
|
||||
result += "\n" + arr[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
string[] split_string_array(const string&in data) {
|
||||
string[] result;
|
||||
if (data.length() == 0) return result;
|
||||
result = data.split("\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
string[] get_string_list_or_split(dictionary@ data, const string&in key) {
|
||||
string[] result = get_string_list(data, key);
|
||||
if (result.length() > 0) return result;
|
||||
string value;
|
||||
if (@data != null && data.get(key, value)) {
|
||||
return split_string_array(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int get_byte_at(const string&in data, int index) {
|
||||
string single = data.substr(index, 1);
|
||||
return character_to_ascii(single);
|
||||
}
|
||||
|
||||
bool find_raw_key(const string&in rawData, const string&in key, int &out pos_after_key) {
|
||||
int key_len = key.length();
|
||||
if (key_len <= 0 || key_len > 65535) return false;
|
||||
int low = key_len & 0xFF;
|
||||
int high = (key_len >> 8) & 0xFF;
|
||||
int limit = rawData.length() - key_len - 2;
|
||||
for (int i = 0; i <= limit; i++) {
|
||||
if (get_byte_at(rawData, i) != low) continue;
|
||||
if (get_byte_at(rawData, i + 1) != high) continue;
|
||||
if (rawData.substr(i + 2, key_len) == key) {
|
||||
pos_after_key = i + 2 + key_len;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_raw_number(const string&in rawData, const string&in key, int &out value) {
|
||||
int pos;
|
||||
if (!find_raw_key(rawData, key, pos)) return false;
|
||||
if (pos >= rawData.length()) return false;
|
||||
int type = get_byte_at(rawData, pos);
|
||||
if (type != 2) return false;
|
||||
if (pos + 1 + 8 > rawData.length()) return false;
|
||||
double result = 0;
|
||||
double multiplier = 1;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
result += get_byte_at(rawData, pos + 1 + i) * multiplier;
|
||||
multiplier *= 256;
|
||||
}
|
||||
value = int(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_raw_bool(const string&in rawData, const string&in key, bool &out value) {
|
||||
int pos;
|
||||
if (!find_raw_key(rawData, key, pos)) return false;
|
||||
if (pos >= rawData.length()) return false;
|
||||
int type = get_byte_at(rawData, pos);
|
||||
if (type != 1) return false;
|
||||
if (pos + 1 >= rawData.length()) return false;
|
||||
value = (get_byte_at(rawData, pos + 1) != 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool load_game_state_from_raw(const string&in rawData) {
|
||||
reset_game_state();
|
||||
|
||||
int value;
|
||||
bool bool_value;
|
||||
|
||||
if (!get_raw_number(rawData, "player_x", value)) return false;
|
||||
x = value;
|
||||
if (!get_raw_number(rawData, "player_health", value)) return false;
|
||||
player_health = value;
|
||||
if (!get_raw_number(rawData, "time_current_day", value)) return false;
|
||||
current_day = value;
|
||||
|
||||
if (get_raw_number(rawData, "player_y", value)) y = value;
|
||||
if (get_raw_number(rawData, "player_facing", value)) facing = value;
|
||||
if (get_raw_number(rawData, "player_base_health", value)) base_max_health = value;
|
||||
if (get_raw_number(rawData, "player_max_health", value)) max_health = value;
|
||||
if (get_raw_number(rawData, "player_favor", value)) favor = value;
|
||||
if (get_raw_number(rawData, "time_current_hour", value)) current_hour = value;
|
||||
if (get_raw_number(rawData, "world_map_size", value)) MAP_SIZE = value;
|
||||
if (get_raw_number(rawData, "world_expanded_area_start", value)) expanded_area_start = value;
|
||||
if (get_raw_number(rawData, "world_expanded_area_end", value)) expanded_area_end = value;
|
||||
if (get_raw_number(rawData, "world_barricade_health", value)) barricade_health = value;
|
||||
if (get_raw_number(rawData, "world_residents_count", value)) residents_count = value;
|
||||
|
||||
if (get_raw_bool(rawData, "world_barricade_initialized", bool_value)) barricade_initialized = bool_value;
|
||||
if (get_raw_bool(rawData, "time_sun_setting_warned", bool_value)) sun_setting_warned = bool_value;
|
||||
if (get_raw_bool(rawData, "time_sunrise_warned", bool_value)) sunrise_warned = bool_value;
|
||||
if (get_raw_bool(rawData, "time_area_expanded_today", bool_value)) area_expanded_today = bool_value;
|
||||
if (get_raw_bool(rawData, "time_invasion_active", bool_value)) invasion_active = bool_value;
|
||||
if (get_raw_bool(rawData, "time_invasion_triggered_today", bool_value)) invasion_triggered_today = bool_value;
|
||||
if (get_raw_bool(rawData, "time_invasion_roll_done_today", bool_value)) invasion_roll_done_today = bool_value;
|
||||
if (get_raw_bool(rawData, "quest_roll_done_today", bool_value)) quest_roll_done_today = bool_value;
|
||||
|
||||
if (get_raw_number(rawData, "time_invasion_start_hour", value)) invasion_start_hour = value;
|
||||
if (get_raw_number(rawData, "time_invasion_chance", value)) invasion_chance = value;
|
||||
if (get_raw_number(rawData, "time_invasion_scheduled_hour", value)) invasion_scheduled_hour = value;
|
||||
|
||||
if (get_raw_number(rawData, "inventory_stones", value)) inv_stones = value;
|
||||
if (get_raw_number(rawData, "inventory_sticks", value)) inv_sticks = value;
|
||||
if (get_raw_number(rawData, "inventory_vines", value)) inv_vines = value;
|
||||
if (get_raw_number(rawData, "inventory_reeds", value)) inv_reeds = value;
|
||||
if (get_raw_number(rawData, "inventory_logs", value)) inv_logs = value;
|
||||
if (get_raw_number(rawData, "inventory_clay", value)) inv_clay = value;
|
||||
if (get_raw_number(rawData, "inventory_small_game", value)) inv_small_game = value;
|
||||
if (get_raw_number(rawData, "inventory_meat", value)) inv_meat = value;
|
||||
if (get_raw_number(rawData, "inventory_skins", value)) inv_skins = value;
|
||||
if (get_raw_number(rawData, "inventory_spears", value)) inv_spears = value;
|
||||
if (get_raw_number(rawData, "inventory_snares", value)) inv_snares = value;
|
||||
if (get_raw_number(rawData, "inventory_axes", value)) inv_axes = value;
|
||||
if (get_raw_number(rawData, "inventory_knives", value)) inv_knives = value;
|
||||
if (get_raw_number(rawData, "inventory_fishing_poles", value)) inv_fishing_poles = value;
|
||||
if (get_raw_number(rawData, "inventory_slings", value)) inv_slings = value;
|
||||
if (get_raw_number(rawData, "inventory_ropes", value)) inv_ropes = value;
|
||||
if (get_raw_number(rawData, "inventory_reed_baskets", value)) inv_reed_baskets = value;
|
||||
if (get_raw_number(rawData, "inventory_clay_pots", value)) inv_clay_pots = value;
|
||||
if (get_raw_number(rawData, "inventory_skin_hats", value)) inv_skin_hats = value;
|
||||
if (get_raw_number(rawData, "inventory_skin_gloves", value)) inv_skin_gloves = value;
|
||||
if (get_raw_number(rawData, "inventory_skin_pants", value)) inv_skin_pants = value;
|
||||
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_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;
|
||||
if (get_raw_bool(rawData, "equipment_sling_equipped", bool_value)) sling_equipped = bool_value;
|
||||
if (get_raw_number(rawData, "equipment_head", value)) equipped_head = value;
|
||||
if (get_raw_number(rawData, "equipment_torso", value)) equipped_torso = value;
|
||||
if (get_raw_number(rawData, "equipment_hands", value)) equipped_hands = value;
|
||||
if (get_raw_number(rawData, "equipment_legs", value)) equipped_legs = value;
|
||||
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_NONE;
|
||||
if (equipped_arms == EQUIP_POUCH && inv_skin_pouches <= 0) equipped_arms = EQUIP_NONE;
|
||||
|
||||
if (inv_small_game_types.length() == 0 && inv_small_game > 0) {
|
||||
for (int i = 0; i < inv_small_game; i++) {
|
||||
inv_small_game_types.insert_last("small game");
|
||||
}
|
||||
}
|
||||
|
||||
if (!barricade_initialized) {
|
||||
init_barricade();
|
||||
} else {
|
||||
if (barricade_health < 0) barricade_health = 0;
|
||||
if (barricade_health > BARRICADE_MAX_HEALTH) barricade_health = BARRICADE_MAX_HEALTH;
|
||||
}
|
||||
spawn_trees(5, 19);
|
||||
|
||||
is_daytime = (current_hour >= 6 && current_hour < 19);
|
||||
hour_timer.restart();
|
||||
update_max_health_from_equipment();
|
||||
return true;
|
||||
}
|
||||
bool save_game_state() {
|
||||
dictionary saveData;
|
||||
|
||||
@@ -218,11 +481,14 @@ bool save_game_state() {
|
||||
saveData.set("player_y", y);
|
||||
saveData.set("player_facing", facing);
|
||||
saveData.set("player_health", player_health);
|
||||
saveData.set("player_base_health", base_max_health);
|
||||
saveData.set("player_max_health", max_health);
|
||||
saveData.set("player_favor", favor);
|
||||
|
||||
saveData.set("inventory_stones", inv_stones);
|
||||
saveData.set("inventory_sticks", inv_sticks);
|
||||
saveData.set("inventory_vines", inv_vines);
|
||||
saveData.set("inventory_reeds", inv_reeds);
|
||||
saveData.set("inventory_logs", inv_logs);
|
||||
saveData.set("inventory_clay", inv_clay);
|
||||
saveData.set("inventory_small_game", inv_small_game);
|
||||
@@ -234,11 +500,57 @@ bool save_game_state() {
|
||||
saveData.set("inventory_knives", inv_knives);
|
||||
saveData.set("inventory_fishing_poles", inv_fishing_poles);
|
||||
saveData.set("inventory_slings", inv_slings);
|
||||
saveData.set("inventory_small_game_types", inv_small_game_types);
|
||||
saveData.set("inventory_ropes", inv_ropes);
|
||||
saveData.set("inventory_reed_baskets", inv_reed_baskets);
|
||||
saveData.set("inventory_clay_pots", inv_clay_pots);
|
||||
saveData.set("inventory_skin_hats", inv_skin_hats);
|
||||
saveData.set("inventory_skin_gloves", inv_skin_gloves);
|
||||
saveData.set("inventory_skin_pants", inv_skin_pants);
|
||||
saveData.set("inventory_skin_tunics", inv_skin_tunics);
|
||||
saveData.set("inventory_moccasins", inv_moccasins);
|
||||
saveData.set("inventory_skin_pouches", inv_skin_pouches);
|
||||
saveData.set("inventory_small_game_types", join_string_array(inv_small_game_types));
|
||||
|
||||
saveData.set("storage_stones", storage_stones);
|
||||
saveData.set("storage_sticks", storage_sticks);
|
||||
saveData.set("storage_vines", storage_vines);
|
||||
saveData.set("storage_reeds", storage_reeds);
|
||||
saveData.set("storage_logs", storage_logs);
|
||||
saveData.set("storage_clay", storage_clay);
|
||||
saveData.set("storage_small_game", storage_small_game);
|
||||
saveData.set("storage_meat", storage_meat);
|
||||
saveData.set("storage_skins", storage_skins);
|
||||
saveData.set("storage_spears", storage_spears);
|
||||
saveData.set("storage_snares", storage_snares);
|
||||
saveData.set("storage_axes", storage_axes);
|
||||
saveData.set("storage_knives", storage_knives);
|
||||
saveData.set("storage_fishing_poles", storage_fishing_poles);
|
||||
saveData.set("storage_slings", storage_slings);
|
||||
saveData.set("storage_ropes", storage_ropes);
|
||||
saveData.set("storage_reed_baskets", storage_reed_baskets);
|
||||
saveData.set("storage_clay_pots", storage_clay_pots);
|
||||
saveData.set("storage_skin_hats", storage_skin_hats);
|
||||
saveData.set("storage_skin_gloves", storage_skin_gloves);
|
||||
saveData.set("storage_skin_pants", storage_skin_pants);
|
||||
saveData.set("storage_skin_tunics", storage_skin_tunics);
|
||||
saveData.set("storage_moccasins", storage_moccasins);
|
||||
saveData.set("storage_skin_pouches", storage_skin_pouches);
|
||||
saveData.set("storage_small_game_types", join_string_array(storage_small_game_types));
|
||||
|
||||
saveData.set("equipment_spear_equipped", spear_equipped);
|
||||
saveData.set("equipment_axe_equipped", axe_equipped);
|
||||
saveData.set("equipment_sling_equipped", sling_equipped);
|
||||
saveData.set("equipment_head", equipped_head);
|
||||
saveData.set("equipment_torso", equipped_torso);
|
||||
saveData.set("equipment_arms", equipped_arms);
|
||||
saveData.set("equipment_hands", equipped_hands);
|
||||
saveData.set("equipment_legs", equipped_legs);
|
||||
saveData.set("equipment_feet", equipped_feet);
|
||||
string[] quickSlotData;
|
||||
for (uint i = 0; i < quick_slots.length(); i++) {
|
||||
quickSlotData.insert_last("" + quick_slots[i]);
|
||||
}
|
||||
saveData.set("equipment_quick_slots", join_string_array(quickSlotData));
|
||||
|
||||
saveData.set("time_current_hour", current_hour);
|
||||
saveData.set("time_current_day", current_day);
|
||||
@@ -248,49 +560,90 @@ bool save_game_state() {
|
||||
saveData.set("time_area_expanded_today", area_expanded_today);
|
||||
saveData.set("time_invasion_active", invasion_active);
|
||||
saveData.set("time_invasion_start_hour", invasion_start_hour);
|
||||
saveData.set("time_invasion_chance", invasion_chance);
|
||||
saveData.set("time_invasion_triggered_today", invasion_triggered_today);
|
||||
saveData.set("time_invasion_roll_done_today", invasion_roll_done_today);
|
||||
saveData.set("time_invasion_scheduled_hour", invasion_scheduled_hour);
|
||||
saveData.set("quest_roll_done_today", quest_roll_done_today);
|
||||
string[] questData;
|
||||
for (uint i = 0; i < quest_queue.length(); i++) {
|
||||
questData.insert_last("" + quest_queue[i]);
|
||||
}
|
||||
saveData.set("quest_queue", join_string_array(questData));
|
||||
|
||||
saveData.set("world_map_size", MAP_SIZE);
|
||||
saveData.set("world_expanded_area_start", expanded_area_start);
|
||||
saveData.set("world_expanded_area_end", expanded_area_end);
|
||||
saveData.set("world_barricade_initialized", barricade_initialized);
|
||||
saveData.set("world_barricade_health", barricade_health);
|
||||
saveData.set("world_expanded_terrain_types", expanded_terrain_types);
|
||||
saveData.set("world_residents_count", residents_count);
|
||||
saveData.set("world_expanded_terrain_types", join_string_array(expanded_terrain_types));
|
||||
|
||||
string[] treeData;
|
||||
for (uint i = 0; i < trees.length(); i++) {
|
||||
treeData.insert_last(serialize_tree(trees[i]));
|
||||
}
|
||||
saveData.set("trees_data", treeData);
|
||||
saveData.set("trees_data", join_string_array(treeData));
|
||||
|
||||
string[] snareData;
|
||||
for (uint i = 0; i < world_snares.length(); i++) {
|
||||
snareData.insert_last(serialize_snare(world_snares[i]));
|
||||
}
|
||||
saveData.set("snares_data", snareData);
|
||||
saveData.set("snares_data", join_string_array(snareData));
|
||||
|
||||
string[] fireData;
|
||||
for (uint i = 0; i < world_fires.length(); i++) {
|
||||
fireData.insert_last(serialize_fire(world_fires[i]));
|
||||
}
|
||||
saveData.set("fires_data", fireData);
|
||||
saveData.set("fires_data", join_string_array(fireData));
|
||||
|
||||
string[] firepitPositions;
|
||||
for (uint i = 0; i < world_firepits.length(); i++) {
|
||||
firepitPositions.insert_last("" + world_firepits[i].position);
|
||||
}
|
||||
saveData.set("firepits_positions", firepitPositions);
|
||||
saveData.set("firepits_positions", join_string_array(firepitPositions));
|
||||
|
||||
string[] herbPositions;
|
||||
for (uint i = 0; i < world_herb_gardens.length(); i++) {
|
||||
herbPositions.insert_last("" + world_herb_gardens[i].position);
|
||||
}
|
||||
saveData.set("herb_gardens_positions", herbPositions);
|
||||
saveData.set("herb_gardens_positions", join_string_array(herbPositions));
|
||||
|
||||
string[] storagePositions;
|
||||
for (uint i = 0; i < world_storages.length(); i++) {
|
||||
storagePositions.insert_last("" + world_storages[i].position);
|
||||
}
|
||||
saveData.set("storages_positions", join_string_array(storagePositions));
|
||||
|
||||
string[] pasturePositions;
|
||||
for (uint i = 0; i < world_pastures.length(); i++) {
|
||||
pasturePositions.insert_last("" + world_pastures[i].position);
|
||||
}
|
||||
saveData.set("pastures_positions", join_string_array(pasturePositions));
|
||||
|
||||
string[] stablePositions;
|
||||
for (uint i = 0; i < world_stables.length(); i++) {
|
||||
stablePositions.insert_last("" + world_stables[i].position);
|
||||
}
|
||||
saveData.set("stables_positions", join_string_array(stablePositions));
|
||||
|
||||
string[] altarPositions;
|
||||
for (uint i = 0; i < world_altars.length(); i++) {
|
||||
altarPositions.insert_last("" + world_altars[i].position);
|
||||
}
|
||||
saveData.set("altars_positions", join_string_array(altarPositions));
|
||||
|
||||
string[] streamData;
|
||||
for (uint i = 0; i < world_streams.length(); i++) {
|
||||
streamData.insert_last(serialize_stream(world_streams[i]));
|
||||
}
|
||||
saveData.set("streams_data", streamData);
|
||||
saveData.set("streams_data", join_string_array(streamData));
|
||||
|
||||
string[] banditData;
|
||||
for (uint i = 0; i < bandits.length(); i++) {
|
||||
banditData.insert_last(serialize_bandit(bandits[i]));
|
||||
}
|
||||
saveData.set("bandits_data", join_string_array(banditData));
|
||||
|
||||
string rawData = saveData.serialize();
|
||||
string encryptedData = encrypt_save_data(rawData);
|
||||
@@ -298,23 +651,38 @@ bool save_game_state() {
|
||||
}
|
||||
|
||||
bool load_game_state() {
|
||||
last_save_error = "";
|
||||
if (!file_exists(SAVE_FILE_PATH)) {
|
||||
last_save_error = "No save file found.";
|
||||
return false;
|
||||
}
|
||||
|
||||
string encryptedData;
|
||||
if (!read_file_string(SAVE_FILE_PATH, encryptedData)) {
|
||||
last_save_error = "Unable to read save file.";
|
||||
return false;
|
||||
}
|
||||
|
||||
string rawData = decrypt_save_data(encryptedData);
|
||||
if (rawData.length() == 0) {
|
||||
dictionary@ saveData = deserialize(rawData);
|
||||
if (@saveData == null || !dictionary_has_keys(saveData)) {
|
||||
saveData = deserialize(encryptedData);
|
||||
}
|
||||
if (@saveData == null || !dictionary_has_keys(saveData)) {
|
||||
if (load_game_state_from_raw(rawData)) {
|
||||
return true;
|
||||
}
|
||||
last_save_error = "Save file is corrupted or unreadable.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dictionary@ saveData = deserialize(rawData);
|
||||
if (@saveData == null) {
|
||||
return false;
|
||||
double version;
|
||||
bool has_version = saveData.get("version", version);
|
||||
if (!has_version) {
|
||||
if (!has_number_key(saveData, "player_x") || !has_number_key(saveData, "player_health") || !has_number_key(saveData, "time_current_day")) {
|
||||
last_save_error = "Save file is missing required data.";
|
||||
return false;
|
||||
}
|
||||
version = 0;
|
||||
}
|
||||
|
||||
reset_game_state();
|
||||
@@ -323,7 +691,7 @@ bool load_game_state() {
|
||||
expanded_area_start = int(get_number(saveData, "world_expanded_area_start", -1));
|
||||
expanded_area_end = int(get_number(saveData, "world_expanded_area_end", -1));
|
||||
|
||||
string[] loadedTerrain = get_string_list(saveData, "world_expanded_terrain_types");
|
||||
string[] loadedTerrain = get_string_list_or_split(saveData, "world_expanded_terrain_types");
|
||||
expanded_terrain_types.resize(0);
|
||||
for (uint i = 0; i < loadedTerrain.length(); i++) {
|
||||
expanded_terrain_types.insert_last(loadedTerrain[i]);
|
||||
@@ -331,6 +699,8 @@ bool load_game_state() {
|
||||
|
||||
barricade_initialized = get_bool(saveData, "world_barricade_initialized", true);
|
||||
barricade_health = int(get_number(saveData, "world_barricade_health", BARRICADE_BASE_HEALTH));
|
||||
residents_count = int(get_number(saveData, "world_residents_count", 0));
|
||||
if (residents_count < 0) residents_count = 0;
|
||||
if (!barricade_initialized) {
|
||||
init_barricade();
|
||||
} else {
|
||||
@@ -343,6 +713,8 @@ bool load_game_state() {
|
||||
facing = int(get_number(saveData, "player_facing", 1));
|
||||
player_health = int(get_number(saveData, "player_health", 10));
|
||||
max_health = int(get_number(saveData, "player_max_health", 10));
|
||||
base_max_health = int(get_number(saveData, "player_base_health", max_health));
|
||||
favor = get_number(saveData, "player_favor", 0.0);
|
||||
|
||||
if (x < 0) x = 0;
|
||||
if (x >= MAP_SIZE) x = MAP_SIZE - 1;
|
||||
@@ -352,6 +724,7 @@ bool load_game_state() {
|
||||
inv_stones = int(get_number(saveData, "inventory_stones", 0));
|
||||
inv_sticks = int(get_number(saveData, "inventory_sticks", 0));
|
||||
inv_vines = int(get_number(saveData, "inventory_vines", 0));
|
||||
inv_reeds = int(get_number(saveData, "inventory_reeds", 0));
|
||||
inv_logs = int(get_number(saveData, "inventory_logs", 0));
|
||||
inv_clay = int(get_number(saveData, "inventory_clay", 0));
|
||||
inv_small_game = int(get_number(saveData, "inventory_small_game", 0));
|
||||
@@ -363,8 +736,17 @@ bool load_game_state() {
|
||||
inv_knives = int(get_number(saveData, "inventory_knives", 0));
|
||||
inv_fishing_poles = int(get_number(saveData, "inventory_fishing_poles", 0));
|
||||
inv_slings = int(get_number(saveData, "inventory_slings", 0));
|
||||
inv_ropes = int(get_number(saveData, "inventory_ropes", 0));
|
||||
inv_reed_baskets = int(get_number(saveData, "inventory_reed_baskets", 0));
|
||||
inv_clay_pots = int(get_number(saveData, "inventory_clay_pots", 0));
|
||||
inv_skin_hats = int(get_number(saveData, "inventory_skin_hats", 0));
|
||||
inv_skin_gloves = int(get_number(saveData, "inventory_skin_gloves", 0));
|
||||
inv_skin_pants = int(get_number(saveData, "inventory_skin_pants", 0));
|
||||
inv_skin_tunics = int(get_number(saveData, "inventory_skin_tunics", 0));
|
||||
inv_moccasins = int(get_number(saveData, "inventory_moccasins", 0));
|
||||
inv_skin_pouches = int(get_number(saveData, "inventory_skin_pouches", 0));
|
||||
|
||||
string[] loadedSmallGameTypes = get_string_list(saveData, "inventory_small_game_types");
|
||||
string[] loadedSmallGameTypes = get_string_list_or_split(saveData, "inventory_small_game_types");
|
||||
inv_small_game_types.resize(0);
|
||||
for (uint i = 0; i < loadedSmallGameTypes.length(); i++) {
|
||||
inv_small_game_types.insert_last(loadedSmallGameTypes[i]);
|
||||
@@ -378,9 +760,71 @@ bool load_game_state() {
|
||||
inv_small_game = inv_small_game_types.length();
|
||||
}
|
||||
|
||||
storage_stones = int(get_number(saveData, "storage_stones", 0));
|
||||
storage_sticks = int(get_number(saveData, "storage_sticks", 0));
|
||||
storage_vines = int(get_number(saveData, "storage_vines", 0));
|
||||
storage_reeds = int(get_number(saveData, "storage_reeds", 0));
|
||||
storage_logs = int(get_number(saveData, "storage_logs", 0));
|
||||
storage_clay = int(get_number(saveData, "storage_clay", 0));
|
||||
storage_small_game = int(get_number(saveData, "storage_small_game", 0));
|
||||
storage_meat = int(get_number(saveData, "storage_meat", 0));
|
||||
storage_skins = int(get_number(saveData, "storage_skins", 0));
|
||||
storage_spears = int(get_number(saveData, "storage_spears", 0));
|
||||
storage_snares = int(get_number(saveData, "storage_snares", 0));
|
||||
storage_axes = int(get_number(saveData, "storage_axes", 0));
|
||||
storage_knives = int(get_number(saveData, "storage_knives", 0));
|
||||
storage_fishing_poles = int(get_number(saveData, "storage_fishing_poles", 0));
|
||||
storage_slings = int(get_number(saveData, "storage_slings", 0));
|
||||
storage_ropes = int(get_number(saveData, "storage_ropes", 0));
|
||||
storage_reed_baskets = int(get_number(saveData, "storage_reed_baskets", 0));
|
||||
storage_clay_pots = int(get_number(saveData, "storage_clay_pots", 0));
|
||||
storage_skin_hats = int(get_number(saveData, "storage_skin_hats", 0));
|
||||
storage_skin_gloves = int(get_number(saveData, "storage_skin_gloves", 0));
|
||||
storage_skin_pants = int(get_number(saveData, "storage_skin_pants", 0));
|
||||
storage_skin_tunics = int(get_number(saveData, "storage_skin_tunics", 0));
|
||||
storage_moccasins = int(get_number(saveData, "storage_moccasins", 0));
|
||||
storage_skin_pouches = int(get_number(saveData, "storage_skin_pouches", 0));
|
||||
|
||||
string[] loadedStorageSmallGameTypes = get_string_list_or_split(saveData, "storage_small_game_types");
|
||||
storage_small_game_types.resize(0);
|
||||
for (uint i = 0; i < loadedStorageSmallGameTypes.length(); i++) {
|
||||
storage_small_game_types.insert_last(loadedStorageSmallGameTypes[i]);
|
||||
}
|
||||
if (storage_small_game_types.length() == 0 && storage_small_game > 0) {
|
||||
for (int i = 0; i < storage_small_game; i++) {
|
||||
storage_small_game_types.insert_last("small game");
|
||||
}
|
||||
} else {
|
||||
storage_small_game = storage_small_game_types.length();
|
||||
}
|
||||
|
||||
spear_equipped = get_bool(saveData, "equipment_spear_equipped", false);
|
||||
axe_equipped = get_bool(saveData, "equipment_axe_equipped", false);
|
||||
sling_equipped = get_bool(saveData, "equipment_sling_equipped", false);
|
||||
equipped_head = int(get_number(saveData, "equipment_head", EQUIP_NONE));
|
||||
equipped_torso = int(get_number(saveData, "equipment_torso", EQUIP_NONE));
|
||||
equipped_arms = int(get_number(saveData, "equipment_arms", EQUIP_NONE));
|
||||
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_NONE;
|
||||
if (equipped_arms == EQUIP_POUCH && inv_skin_pouches <= 0) equipped_arms = EQUIP_NONE;
|
||||
reset_quick_slots();
|
||||
string[] loadedQuickSlots = get_string_list_or_split(saveData, "equipment_quick_slots");
|
||||
uint slot_count = loadedQuickSlots.length();
|
||||
if (slot_count > quick_slots.length()) slot_count = quick_slots.length();
|
||||
for (uint i = 0; i < slot_count; i++) {
|
||||
int slot_value = parse_int(loadedQuickSlots[i]);
|
||||
if (slot_value >= EQUIP_NONE && slot_value <= EQUIP_POUCH) {
|
||||
quick_slots[i] = slot_value;
|
||||
}
|
||||
}
|
||||
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));
|
||||
@@ -389,6 +833,25 @@ bool load_game_state() {
|
||||
area_expanded_today = get_bool(saveData, "time_area_expanded_today", false);
|
||||
invasion_active = get_bool(saveData, "time_invasion_active", false);
|
||||
invasion_start_hour = int(get_number(saveData, "time_invasion_start_hour", -1));
|
||||
invasion_chance = int(get_number(saveData, "time_invasion_chance", 25));
|
||||
invasion_triggered_today = get_bool(saveData, "time_invasion_triggered_today", false);
|
||||
invasion_roll_done_today = get_bool(saveData, "time_invasion_roll_done_today", false);
|
||||
invasion_scheduled_hour = int(get_number(saveData, "time_invasion_scheduled_hour", -1));
|
||||
if (invasion_chance < 0) invasion_chance = 0;
|
||||
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;
|
||||
quest_roll_done_today = get_bool(saveData, "quest_roll_done_today", false);
|
||||
|
||||
quest_queue.resize(0);
|
||||
string[] loadedQuests = get_string_list_or_split(saveData, "quest_queue");
|
||||
for (uint i = 0; i < loadedQuests.length(); i++) {
|
||||
int quest_type = parse_int(loadedQuests[i]);
|
||||
if (quest_type >= 0 && quest_type < QUEST_TYPE_COUNT) {
|
||||
quest_queue.insert_last(quest_type);
|
||||
if (quest_queue.length() >= QUEST_MAX_ACTIVE) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_hour < 0) current_hour = 0;
|
||||
if (current_hour > 23) current_hour = 23;
|
||||
@@ -397,7 +860,7 @@ bool load_game_state() {
|
||||
is_daytime = (current_hour >= 6 && current_hour < 19);
|
||||
hour_timer.restart();
|
||||
|
||||
string[] treeData = get_string_list(saveData, "trees_data");
|
||||
string[] treeData = get_string_list_or_split(saveData, "trees_data");
|
||||
for (uint i = 0; i < treeData.length(); i++) {
|
||||
string[]@ parts = treeData[i].split("|");
|
||||
if (parts.length() < 8) continue;
|
||||
@@ -415,7 +878,7 @@ bool load_game_state() {
|
||||
trees.insert_last(tree);
|
||||
}
|
||||
|
||||
string[] snareData = get_string_list(saveData, "snares_data");
|
||||
string[] snareData = get_string_list_or_split(saveData, "snares_data");
|
||||
for (uint i = 0; i < snareData.length(); i++) {
|
||||
string[]@ parts = snareData[i].split("|");
|
||||
if (parts.length() < 6) continue;
|
||||
@@ -431,7 +894,7 @@ bool load_game_state() {
|
||||
world_snares.insert_last(snare);
|
||||
}
|
||||
|
||||
string[] fireData = get_string_list(saveData, "fires_data");
|
||||
string[] fireData = get_string_list_or_split(saveData, "fires_data");
|
||||
for (uint i = 0; i < fireData.length(); i++) {
|
||||
string[]@ parts = fireData[i].split("|");
|
||||
if (parts.length() < 3) continue;
|
||||
@@ -444,17 +907,37 @@ bool load_game_state() {
|
||||
world_fires.insert_last(fire);
|
||||
}
|
||||
|
||||
string[] firepitPositions = get_string_list(saveData, "firepits_positions");
|
||||
string[] firepitPositions = get_string_list_or_split(saveData, "firepits_positions");
|
||||
for (uint i = 0; i < firepitPositions.length(); i++) {
|
||||
add_world_firepit(parse_int(firepitPositions[i]));
|
||||
}
|
||||
|
||||
string[] herbPositions = get_string_list(saveData, "herb_gardens_positions");
|
||||
string[] herbPositions = get_string_list_or_split(saveData, "herb_gardens_positions");
|
||||
for (uint i = 0; i < herbPositions.length(); i++) {
|
||||
add_world_herb_garden(parse_int(herbPositions[i]));
|
||||
}
|
||||
|
||||
string[] streamData = get_string_list(saveData, "streams_data");
|
||||
string[] storagePositions = get_string_list_or_split(saveData, "storages_positions");
|
||||
for (uint i = 0; i < storagePositions.length(); i++) {
|
||||
add_world_storage(parse_int(storagePositions[i]));
|
||||
}
|
||||
|
||||
string[] pasturePositions = get_string_list_or_split(saveData, "pastures_positions");
|
||||
for (uint i = 0; i < pasturePositions.length(); i++) {
|
||||
add_world_pasture(parse_int(pasturePositions[i]));
|
||||
}
|
||||
|
||||
string[] stablePositions = get_string_list_or_split(saveData, "stables_positions");
|
||||
for (uint i = 0; i < stablePositions.length(); i++) {
|
||||
add_world_stable(parse_int(stablePositions[i]));
|
||||
}
|
||||
|
||||
string[] altarPositions = get_string_list_or_split(saveData, "altars_positions");
|
||||
for (uint i = 0; i < altarPositions.length(); i++) {
|
||||
add_world_altar(parse_int(altarPositions[i]));
|
||||
}
|
||||
|
||||
string[] streamData = get_string_list_or_split(saveData, "streams_data");
|
||||
for (uint i = 0; i < streamData.length(); i++) {
|
||||
string[]@ parts = streamData[i].split("|");
|
||||
if (parts.length() < 2) continue;
|
||||
@@ -465,6 +948,40 @@ bool load_game_state() {
|
||||
add_world_stream(startPos, width);
|
||||
}
|
||||
|
||||
string[] banditData = get_string_list_or_split(saveData, "bandits_data");
|
||||
for (uint i = 0; i < banditData.length(); i++) {
|
||||
string[]@ parts = banditData[i].split("|");
|
||||
if (parts.length() < 6) continue;
|
||||
|
||||
int pos = parse_int(parts[0]);
|
||||
int health = parse_int(parts[1]);
|
||||
string weapon = parts[2];
|
||||
string state = parts[3];
|
||||
int wander_dir = parse_int(parts[4]);
|
||||
int move_int = parse_int(parts[5]);
|
||||
|
||||
// Create bandit with dummy expansion area (position will be overridden)
|
||||
Bandit@ b = Bandit(pos, pos, pos);
|
||||
b.position = pos;
|
||||
b.health = health;
|
||||
b.weapon_type = weapon;
|
||||
b.behavior_state = state;
|
||||
b.wander_direction = wander_dir;
|
||||
b.move_interval = move_int;
|
||||
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);
|
||||
}
|
||||
|
||||
update_ambience(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user