From 7c889d5a80a59d3281775c3ea731f4e640295353 Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Tue, 3 Dec 2024 18:56:44 +0100 Subject: working on save load --- src/scenes/loading_world_scene.c | 2 +- src/scenes/save_state_select.c | 466 ++++++++++++++++++++++++++++++++++++++- src/scenes/world_map.c | 4 +- 3 files changed, 467 insertions(+), 5 deletions(-) (limited to 'src/scenes') diff --git a/src/scenes/loading_world_scene.c b/src/scenes/loading_world_scene.c index aa3472e..bdcee85 100644 --- a/src/scenes/loading_world_scene.c +++ b/src/scenes/loading_world_scene.c @@ -20,7 +20,7 @@ static void* start_loading_world_t(void* arg) // Load from file here } else { - world_to_load = world_create_new(); + world_to_load = world_create_new(true); } #ifdef MODE_DEBUG diff --git a/src/scenes/save_state_select.c b/src/scenes/save_state_select.c index a901864..026362d 100644 --- a/src/scenes/save_state_select.c +++ b/src/scenes/save_state_select.c @@ -1,4 +1,3 @@ - typedef struct t_save_file_entry { bool exists; @@ -117,6 +116,465 @@ extern world* _active_world; static void load_save_file(s32 index) { log_info("Loading save file."); + + save_file_entry entry = save_entries[index]; + if (!entry.exists) return; + + file_content save_file = platform_read_file_content(entry.path, "rb"); + if (save_file.file_error) return; + + printf("Loading file: %s.\n", entry.path); + + cJSON *json_object = cJSON_Parse(save_file.content); + if (!json_object) { + log_info("Failed to load save file."); + game_set_active_scene(GAME_STATE_ERROR); + return; + } + + world* new_world = world_create_new(false); + if (!new_world) { + log_info("Failed to load save file."); + game_set_active_scene(GAME_STATE_ERROR); + return; + } + + // TODO return on error here in release. + #define GET_PROP(_prop, _obj, _str)\ + cJSON* _prop = cJSON_GetObjectItem(_obj, _str);\ + if (!_prop) {\ + log_info("Failed to load save file.");\ + game_set_active_scene(GAME_STATE_ERROR);\ + } + + GET_PROP(version, json_object, "version"); + if (version->valueint != 1) return; + + GET_PROP(simulation_time, json_object, "simulation_time"); + new_world->simulation_time = simulation_time->valueint; + + GET_PROP(start_year, json_object, "start_year"); + new_world->start_year = start_year->valueint; + + GET_PROP(money, json_object, "money"); + new_world->money = money->valuedouble; + + GET_PROP(next_id, json_object, "next_id"); + new_world->next_id = next_id->valueint; + + GET_PROP(simulation_speed, json_object, "simulation_speed"); + new_world->simulation_speed = simulation_speed->valueint; + + GET_PROP(days_since_last_random_event, json_object, "days_since_last_random_event"); + new_world->days_since_last_random_event = days_since_last_random_event->valueint; + + GET_PROP(bank_info, json_object, "bank_info"); + GET_PROP(loan1, bank_info, "loan1"); + GET_PROP(loan2, bank_info, "loan2"); + GET_PROP(loan3, bank_info, "loan3"); + + { // Loan 1 + GET_PROP(amount, loan1, "amount"); + new_world->bank_info.loan1.amount = amount->valueint; + + GET_PROP(interest, loan1, "interest"); + new_world->bank_info.loan1.interest = interest->valuedouble; + + GET_PROP(days_left, loan1, "days_left"); + new_world->bank_info.loan1.days_left = days_left->valueint; + + GET_PROP(monthly_payment, loan1, "monthly_payment"); + new_world->bank_info.loan1.monthly_payment = monthly_payment->valuedouble; + + GET_PROP(is_active, loan1, "is_active"); + new_world->bank_info.loan1.is_active = is_active->valueint; + } + + { // Loan 2 + GET_PROP(amount, loan2, "amount"); + new_world->bank_info.loan2.amount = amount->valueint; + + GET_PROP(interest, loan2, "interest"); + new_world->bank_info.loan2.interest = interest->valuedouble; + + GET_PROP(days_left, loan2, "days_left"); + new_world->bank_info.loan2.days_left = days_left->valueint; + + GET_PROP(monthly_payment, loan2, "monthly_payment"); + new_world->bank_info.loan2.monthly_payment = monthly_payment->valuedouble; + + GET_PROP(is_active, loan2, "is_active"); + new_world->bank_info.loan2.is_active = is_active->valueint; + } + + { // Loan 3 + GET_PROP(amount, loan3, "amount"); + new_world->bank_info.loan3.amount = amount->valueint; + + GET_PROP(interest, loan3, "interest"); + new_world->bank_info.loan3.interest = interest->valuedouble; + + GET_PROP(days_left, loan3, "days_left"); + new_world->bank_info.loan3.days_left = days_left->valueint; + + GET_PROP(monthly_payment, loan3, "monthly_payment"); + new_world->bank_info.loan3.monthly_payment = monthly_payment->valuedouble; + + GET_PROP(is_active, loan3, "is_active"); + new_world->bank_info.loan3.is_active = is_active->valueint; + } + + GET_PROP(investments, json_object, "investments"); + { + GET_PROP(marketing, investments, "marketing"); + new_world->investments.marketing = marketing->valueint; + + GET_PROP(human_resources, investments, "human_resources"); + new_world->investments.human_resources = human_resources->valueint; + + GET_PROP(training, investments, "training"); + new_world->investments.training = training->valueint; + + GET_PROP(legal, investments, "legal"); + new_world->investments.legal = legal->valueint; + } + + GET_PROP(log, json_object, "log"); + { + GET_PROP(write_cursor, log, "write_cursor"); + new_world->log.write_cursor = write_cursor->valueint; + + GET_PROP(has_unread_messages, log, "has_unread_messages"); + new_world->log.has_unread_messages = has_unread_messages->valueint; + + GET_PROP(events, log, "events"); + cJSON* event_iter; + cJSON_ArrayForEach(event_iter, events) + { + GET_PROP(type, event_iter, "type"); + GET_PROP(message, event_iter, "message"); + + event new_event; + new_event.data = 0; + new_event.type = type->valueint; + memset(&new_event.job_time, 0, sizeof(scheduled_job_time)); + string_copyn(new_event.message, message->valuestring, MAX_EVENT_MESSAGE_LENGTH); + + array_push(&new_world->log.events, &new_event); + } + } + + GET_PROP(locations, json_object, "locations"); + cJSON* location_iter; + cJSON_ArrayForEach(location_iter, locations) + { + GET_PROP(name, location_iter, "name"); + + world_location* existing_loc = world_get_location_by_name(new_world, name->valuestring); + if (existing_loc == 0) { + printf("LOAD ERROR: location '%s' does not exist.\n", name->valuestring); + continue; + } + + GET_PROP(is_owned, location_iter, "is_owned"); + existing_loc->is_owned = is_owned->valueint; + + GET_PROP(purchase_year, location_iter, "purchase_year"); + existing_loc->purchase_year = purchase_year->valueint; + + GET_PROP(score, location_iter, "score"); + existing_loc->score = score->valuedouble; + + GET_PROP(employees, location_iter, "employees"); + cJSON* employee_iter; + cJSON_ArrayForEach(employee_iter, employees) + { + employee* employee1 = mem_alloc(sizeof(employee)); + + GET_PROP(id, employee_iter, "id"); + employee1->id = (u32)id->valuedouble; + + GET_PROP(name, employee_iter, "name"); + string_copyn(employee1->name, name->valuestring, MAX_EMPLOYEE_NAME_LENGTH); + + GET_PROP(age, employee_iter, "age"); + employee1->age = age->valueint; + + GET_PROP(experience, employee_iter, "experience"); + employee1->experience = experience->valuedouble; + + GET_PROP(salary, employee_iter, "salary"); + employee1->salary = salary->valuedouble; + + GET_PROP(happiness, employee_iter, "happiness"); + employee1->happiness = happiness->valuedouble; + + GET_PROP(days_below_happiness_treshold, employee_iter, "days_below_happiness_treshold"); + employee1->days_below_happiness_treshold = happiness->valueint; + + GET_PROP(current_location_id, employee_iter, "current_location_id"); + employee1->current_location_id = (u32)current_location_id->valuedouble; + + GET_PROP(original_location_id, employee_iter, "original_location_id"); + employee1->original_location_id = (u32)original_location_id->valuedouble; + + GET_PROP(active_job_id, employee_iter, "active_job_id"); + employee1->active_job_id = active_job_id->valueint; + + employee1->assigned_truck = 0; // Is set after loading trucks. + + GET_PROP(portrait_hair_type, employee_iter, "portrait_hair_type"); + employee1->portrait_hair_type = portrait_hair_type->valueint; + + GET_PROP(hair_color, employee_iter, "hair_color"); + GET_PROP(face_color, employee_iter, "face_color"); + GET_PROP(body_color, employee_iter, "body_color"); + + { // hair_color + GET_PROP(r, hair_color, "r"); + GET_PROP(g, hair_color, "g"); + GET_PROP(b, hair_color, "b"); + GET_PROP(a, hair_color, "a"); + employee1->hair_color = rgba(r->valueint, g->valueint, b->valueint, a->valueint); + } + + { // face_color + GET_PROP(r, face_color, "r"); + GET_PROP(g, face_color, "g"); + GET_PROP(b, face_color, "b"); + GET_PROP(a, face_color, "a"); + employee1->face_color = rgba(r->valueint, g->valueint, b->valueint, a->valueint); + } + + { // body_color + GET_PROP(r, body_color, "r"); + GET_PROP(g, body_color, "g"); + GET_PROP(b, body_color, "b"); + GET_PROP(a, body_color, "a"); + employee1->body_color = rgba(r->valueint, g->valueint, b->valueint, a->valueint); + } + + array_push(&existing_loc->employees, &employee1); + } + + GET_PROP(job_offers, location_iter, "job_offers"); + cJSON* joboffer_iter; + cJSON_ArrayForEach(joboffer_iter, job_offers) + { + job_offer new_offer; + new_offer.connections = array_create(sizeof(world_location*)); + + GET_PROP(id, joboffer_iter, "id"); + new_offer.id = id->valueint; + + GET_PROP(expire_date, joboffer_iter, "expire_date"); + new_offer.expire_date = (s64)expire_date->valuedouble; + + GET_PROP(company_id, joboffer_iter, "company_id"); + new_offer.company = world_get_company_by_name(new_world, company_id->valuestring); + + GET_PROP(prod, joboffer_iter, "product"); + new_offer.product = world_get_product_by_name(new_world, prod->valuestring); + + GET_PROP(shipday_count, joboffer_iter, "shipday_count"); + new_offer.shipday_count = (s32)shipday_count->valueint; + + GET_PROP(reward, joboffer_iter, "reward"); + new_offer.reward = (u32)reward->valueint; + + GET_PROP(total_distance, joboffer_iter, "total_distance"); + new_offer.total_distance = (float)total_distance->valuedouble; + + GET_PROP(boat_distance, joboffer_iter, "boat_distance"); + new_offer.boat_distance = (float)boat_distance->valuedouble; + + GET_PROP(duration_sec_min, joboffer_iter, "duration_sec_min"); + new_offer.duration_sec_min = (time_t)duration_sec_min->valuedouble; + + GET_PROP(duration_sec_max, joboffer_iter, "duration_sec_max"); + new_offer.duration_sec_max = (time_t)duration_sec_max->valuedouble; + + GET_PROP(duration_sec_min_excluding_boat, joboffer_iter, "duration_sec_min_excluding_boat"); + new_offer.duration_sec_min_excluding_boat = (time_t)duration_sec_min_excluding_boat->valuedouble; + + GET_PROP(shipdays, joboffer_iter, "shipdays"); + cJSON* shipday_iter; + int shipday_index = 0; + cJSON_ArrayForEach(shipday_iter, shipdays) + { + new_offer.shipdays[shipday_index] = (weekday)shipday_iter->valueint; + shipday_index++; + } + + GET_PROP(connections, joboffer_iter, "connections"); + cJSON* connection_iter; + cJSON_ArrayForEach(connection_iter, connections) + { + u64 id = (u32)connection_iter->valuedouble; + world_location* loc = get_world_location_by_id(new_world, id); + if (loc) array_push(&new_offer.connections, &loc); + } + + array_push(&existing_loc->job_offers, &new_offer); + } + + GET_PROP(resumes, location_iter, "resumes"); + cJSON* resume_iter; + cJSON_ArrayForEach(resume_iter, resumes) + { + resume new_resume; + new_resume.animation = animation_create(RESUME_FADEOUT_MS); + + GET_PROP(expire_date, resume_iter, "expire_date"); + new_resume.expire_date = (s64)expire_date->valuedouble; + + new_resume.hired = false; + + // Employee is not hired yet so just make up a new employee. + new_resume.employee = create_employee(new_world, existing_loc); + + array_push(&existing_loc->resumes, &new_resume); + } + + GET_PROP(trucks, location_iter, "trucks"); + cJSON* truck_iter; + cJSON_ArrayForEach(truck_iter, trucks) + { + GET_PROP(type, truck_iter, "type"); + s32 truck_type = (s32)type->valuedouble; + + truck* new_truck = world_get_truck_by_type(new_world, truck_type); + + GET_PROP(id, truck_iter, "id"); + new_truck->id = (s32)id->valuedouble; + + GET_PROP(employee_id, truck_iter, "employee_id"); + u32 emp_id = (u32)employee_id->valuedouble; + + employee* emp = 0; + if (emp_id == 0) { + new_truck->assigned_employee = 0; + } + else { + emp = get_employee_by_id(existing_loc, emp_id); + new_truck->assigned_employee = emp; + } + + array_push(&existing_loc->trucks, new_truck); + + if (emp) { + emp->assigned_truck = array_at(&existing_loc->trucks, existing_loc->trucks.length-1); + } + } + + GET_PROP(schedule, location_iter, "schedule"); + cJSON* job_iter; + cJSON_ArrayForEach(job_iter, schedule) + { + scheduled_job existing_job; + existing_job.location = existing_loc; + + GET_PROP(trust, job_iter, "trust"); + existing_job.trust = (float)trust->valuedouble; + + GET_PROP(offer, job_iter, "offer"); + { // Load job offer of existing job. + job_offer new_offer; + new_offer.connections = array_create(sizeof(world_location*)); + + GET_PROP(id, offer, "id"); + new_offer.id = id->valueint; + + GET_PROP(expire_date, offer, "expire_date"); + new_offer.expire_date = (s64)expire_date->valuedouble; + + GET_PROP(company_id, offer, "company_id"); + new_offer.company = world_get_company_by_name(new_world, company_id->valuestring); + + GET_PROP(prod, offer, "product"); + new_offer.product = world_get_product_by_name(new_world, prod->valuestring); + + GET_PROP(shipday_count, offer, "shipday_count"); + new_offer.shipday_count = (s32)shipday_count->valueint; + + GET_PROP(reward, offer, "reward"); + new_offer.reward = (u32)reward->valueint; + + GET_PROP(total_distance, offer, "total_distance"); + new_offer.total_distance = (float)total_distance->valuedouble; + + GET_PROP(boat_distance, offer, "boat_distance"); + new_offer.boat_distance = (float)boat_distance->valuedouble; + + GET_PROP(duration_sec_min, offer, "duration_sec_min"); + new_offer.duration_sec_min = (time_t)duration_sec_min->valuedouble; + + GET_PROP(duration_sec_max, offer, "duration_sec_max"); + new_offer.duration_sec_max = (time_t)duration_sec_max->valuedouble; + + GET_PROP(duration_sec_min_excluding_boat, offer, "duration_sec_min_excluding_boat"); + new_offer.duration_sec_min_excluding_boat = (time_t)duration_sec_min_excluding_boat->valuedouble; + + GET_PROP(shipdays, offer, "shipdays"); + cJSON* shipday_iter; + int shipday_index = 0; + cJSON_ArrayForEach(shipday_iter, shipdays) + { + new_offer.shipdays[shipday_index] = (weekday)shipday_iter->valueint; + shipday_index++; + } + + GET_PROP(connections, offer, "connections"); + cJSON* connection_iter; + cJSON_ArrayForEach(connection_iter, connections) + { + u64 id = (u32)connection_iter->valuedouble; + world_location* loc = get_world_location_by_id(new_world, id); + if (loc) array_push(&new_offer.connections, &loc); + } + + existing_job.offer = new_offer; + } + + for (s32 i = 0; i < MAX_SHIPDAYS; i++) { + existing_job.timeslots[i] = (scheduled_job_time){-1, -1, 0, 0}; + } + + GET_PROP(timeslots, job_iter, "timeslots"); + cJSON* timeslot_iter; + int timeslot_index = 0; + cJSON_ArrayForEach(timeslot_iter, timeslots) + { + scheduled_job_time job_time; + + GET_PROP(day, timeslot_iter, "day"); + job_time.day = (s16)trust->valueint; + + GET_PROP(timeslot, timeslot_iter, "timeslot"); + job_time.timeslot = (s16)timeslot->valueint; + + GET_PROP(stay_at_destination, timeslot_iter, "stay_at_destination"); + job_time.stay_at_destination = (bool)stay_at_destination->valueint; + + GET_PROP(employee_id, timeslot_iter, "assignee_id"); + u32 emp_id = (u32)employee_id->valuedouble; + + job_time.assignee = get_employee_by_id(existing_loc, emp_id); + + existing_job.timeslots[timeslot_index] = job_time; + timeslot_index++; + } + + array_push(&existing_loc->schedule.jobs, &existing_job); + } + } + + + world_map_set_active_world(new_world); + enable_insights_for_current_month(new_world); + world_update_location_scores(new_world); + + game_set_active_scene(GAME_STATE_WORLD_MAP); } static void write_save_file(s32 index) @@ -139,6 +597,7 @@ static void write_save_file(s32 index) cJSON_AddItemToObject(world, "name", cJSON_CreateString(name_buf)); } + cJSON_AddItemToObject(world, "version", cJSON_CreateNumber(1)); cJSON_AddItemToObject(world, "save_index", cJSON_CreateNumber(index)); cJSON_AddItemToObject(world, "simulation_time", cJSON_CreateNumber(_active_world->simulation_time)); @@ -198,7 +657,7 @@ static void write_save_file(s32 index) event* e = array_at(&_active_world->log.events, i); cJSON *event = cJSON_CreateObject(); cJSON_AddItemToObject(event, "type", cJSON_CreateNumber(e->type)); - cJSON_AddItemToObject(event, "message", cJSON_CreateString (e->message)); + cJSON_AddItemToObject(event, "message", cJSON_CreateString(e->message)); cJSON_AddItemToArray(entries, event); } @@ -215,6 +674,7 @@ static void write_save_file(s32 index) if (!location->is_owned) continue; cJSON *loc = cJSON_CreateObject(); + cJSON_AddItemToObject(loc, "name", cJSON_CreateString(location->name)); cJSON_AddItemToObject(loc, "is_owned", cJSON_CreateNumber(location->is_owned)); cJSON_AddItemToObject(loc, "purchase_year", cJSON_CreateNumber(location->purchase_year)); cJSON_AddItemToObject(loc, "score", cJSON_CreateNumber(location->score)); @@ -274,6 +734,7 @@ static void write_save_file(s32 index) cJSON *offer = cJSON_CreateObject(); cJSON_AddItemToObject(offer, "id", cJSON_CreateNumber(o->id)); + cJSON_AddItemToObject(offer, "reward", cJSON_CreateNumber(o->reward)); cJSON_AddItemToObject(offer, "expire_date", cJSON_CreateNumber(o->expire_date)); cJSON_AddItemToObject(offer, "company_id", cJSON_CreateString(o->company->name)); cJSON_AddItemToObject(offer, "product", cJSON_CreateString(o->product->name)); @@ -368,6 +829,7 @@ static void write_save_file(s32 index) cJSON *offer = cJSON_CreateObject(); cJSON_AddItemToObject(offer, "id", cJSON_CreateNumber(scheduled_job->offer.id)); cJSON_AddItemToObject(offer, "expire_date", cJSON_CreateNumber(scheduled_job->offer.expire_date)); + cJSON_AddItemToObject(offer, "reward", cJSON_CreateNumber(scheduled_job->offer.reward)); cJSON_AddItemToObject(offer, "company_id", cJSON_CreateString(scheduled_job->offer.company->name)); cJSON_AddItemToObject(offer, "product", cJSON_CreateString(scheduled_job->offer.product->name)); cJSON_AddItemToObject(offer, "shipday_count", cJSON_CreateNumber(scheduled_job->offer.shipday_count)); diff --git a/src/scenes/world_map.c b/src/scenes/world_map.c index f96ba0e..3ef4cdb 100644 --- a/src/scenes/world_map.c +++ b/src/scenes/world_map.c @@ -667,16 +667,16 @@ static void world_map_draw_event_log(platform_window* window) event* e = array_at(&_active_world->log.events, read_cursor); float inner_pad = 5*scale; - s32 texth = renderer->render_text_cutoff(fnt, text_x+inner_pad, text_y+inner_pad, e->message, COLOR_TEXT, text_w-(inner_pad*2)); s32 highlight_w = text_w; s32 highlight_h = texth+(inner_pad); - if (e->type != EVENT_TYPE_INFO && mouse_interacts(text_x, text_y, highlight_w, highlight_h)) { + if (e->data != 0 && e->type != EVENT_TYPE_INFO && mouse_interacts(text_x, text_y, highlight_w, highlight_h)) { platform_set_cursor(window, CURSOR_POINTER); renderer->render_rectangle(text_x, text_y, text_w, highlight_h, rgba(255,255,255,20)); + // data is 0 when loading from save file. if (is_left_clicked()) { switch (e->type) { -- cgit v1.2.3-70-g09d2