summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--src/include/world.h8
-rw-r--r--src/scenes/place_detail.c31
-rw-r--r--src/world.c58
4 files changed, 92 insertions, 8 deletions
diff --git a/README.md b/README.md
index 4b3d1d4..f614691 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
Truck logistics management game written using C + OpenGL. Uses SDL2 SDL2_Mixer for audio.
Video: https://www.youtube.com/watch?v=vd9a-LMGzrs&ab_channel=Aldrik
+
+Heuristics:
+location score is based on: schedule efficiency 60%, employee happiness 10%, customer trust 30% \ No newline at end of file
diff --git a/src/include/world.h b/src/include/world.h
index 11ac92e..a719e57 100644
--- a/src/include/world.h
+++ b/src/include/world.h
@@ -29,6 +29,8 @@
typedef struct t_world_location world_location;
typedef struct t_employee employee;
+
+
#define WORK_HOUR_START 0
#define WORK_HOUR_END 24
#define TIME_SLOTS_PER_HOUR 4
@@ -39,7 +41,8 @@ typedef struct t_employee employee;
#define MAX_EMPLOYEE_COUNT (TIME_SLOTS_PER_WEEK)
#define MAX_TRUCK_COUNT (TIME_SLOTS_PER_WEEK)
-#define MISSED_DELIVERY_TRUST_PENALTY (0.5f)
+#define JOB_STARTING_TRUST 0.8f
+#define MISSED_DELIVERY_TRUST_PENALTY (0.1f)
#define MAX_EFFECTIVE_EXPERIENCE 25.0f // anything past 25 years of experience has no extra positives.
#define SHIPTIME_DURATION_MULTIPLIER_MAX 1.0f
#define SHIPTIME_DURATION_MULTIPLIER_MIN 1.15f
@@ -145,7 +148,7 @@ typedef struct t_employee
struct tm hire_date;
u8 experience;
float salary;
- float happiness;
+ float happiness; // 0-1
s16 days_below_happiness_treshold;
u32 current_location_id;
u32 original_location_id;
@@ -242,6 +245,7 @@ typedef struct t_world_location
schedule schedule;
u16 purchase_year;
array insights;
+ float score; // 0-1
// Dynamic
array connections;
diff --git a/src/scenes/place_detail.c b/src/scenes/place_detail.c
index 707ae0f..4519cfa 100644
--- a/src/scenes/place_detail.c
+++ b/src/scenes/place_detail.c
@@ -131,7 +131,7 @@ static scheduled_job create_empty_job_schedule(job_offer* job)
scheduled_job new_job;
new_job.location = _active_location;
new_job.offer = *job;
- new_job.trust = 1.0f;
+ new_job.trust = JOB_STARTING_TRUST;
for (s32 i = 0; i < MAX_SHIPDAYS; i++) {
new_job.timeslots[i] = (scheduled_job_time){-1, -1, 0, 0};
}
@@ -1567,11 +1567,34 @@ static tab place_detail_draw_tabs(platform_window* window)
return place_detail_draw_tab_bg(window);
}
+#define DRAW_STARS(_x, _y, _txt, _count){\
+s32 textw = renderer->render_text(fnt, _x, _y, _txt, COLOR_TEXT);\
+_x += (scale*5);\
+for (s32 i = 0; i < 5; i++)\
+{\
+ if (i < _count) renderer->render_image(img_star, _x + textw + (i*(fnt->px_h+2)), _y, fnt->px_h, fnt->px_h);\
+ else renderer->render_image_tint(img_star, _x + textw + (i*(fnt->px_h+2)), _y, fnt->px_h, fnt->px_h, rgba(255,255,255,30));\
+}}
+
+static void place_detail_draw_location_stats(platform_window* window)
+{
+ font* fnt = fnt_rd20;
+ float text_pad = scale * 40.0;
+
+ //s32 w = (area.w * 0.9 - (offset*2));
+
+ s32 text_x = area.x + text_pad + (area.w*0.75);
+ s32 text_y = area.y + text_pad + (area.w*0.05);
+
+ DRAW_STARS(text_x, text_y, "Score: ", 5);
+}
+
static void place_detail_draw_title(platform_window* window)
{
char buf[200];
if (current_detail_state == PLACE_DETAIL_SHOW_MAIN) {
strcpy(buf, _active_location->name);
+ place_detail_draw_location_stats(window);
}
else if (current_detail_state == PLACE_DETAIL_SHOW_RESUMES) {
strcpy(buf, "Hire new employees");
@@ -1596,8 +1619,8 @@ static void place_detail_draw_title(platform_window* window)
font* fnt = fnt_rd36;
float text_pad = scale * 40.0;
- s32 text_x = text_pad + area.x + (area.w*0.05);
- s32 text_y = text_pad + area.y + (area.w*0.05);
+ s32 text_x = area.x + text_pad + (area.w*0.05);
+ s32 text_y = area.y + text_pad + (area.w*0.05);
// Title
{
@@ -1739,7 +1762,7 @@ void place_detail_scene_render(platform_window* window)
if (selected_tab_index == PLACE_DETAIL_SCHEDULE) {
selected_tab_index = PLACE_DETAIL_SHOW_MAIN;
current_detail_state = PLACE_DETAIL_SHOW_SCHEDULE;
- }
+ }
}
if (current_detail_state == PLACE_DETAIL_SHOW_RESUMES) {
place_detail_draw_resumes(window);
diff --git a/src/world.c b/src/world.c
index db8ce7d..3226937 100644
--- a/src/world.c
+++ b/src/world.c
@@ -692,7 +692,7 @@ static void world_assign_new_job_offers(world* world)
total_dist += distance_between_location(source, dest);
}
new_offer.total_distance = total_dist;
- new_offer.reward = (u32)(new_offer.total_distance * 2.1); // -1 because source is is connection list.
+ new_offer.reward = (u32)(new_offer.total_distance * 2.1);
// lets assume most experienced drivers drive at 90km/h
double min_duration_hours = (new_offer.total_distance/90.0);
@@ -976,7 +976,12 @@ static void world_update_active_jobs(world* world)
i--;
}
else { // Job is done, return to original location if not staying.
- if (sc_job) sc_job->trust += (0.1f / sc_job->trust); // If job is still available, update trust.
+ if (sc_job) { // If job is still available, update trust.
+ sc_job->trust += (0.01f / sc_job->trust);
+ if (sc_job->trust > 1.0f) {
+ sc_job->trust = 1.0f;
+ }
+ }
ADD_INCOME(world, endpoints.source, income_from_trips, job->offer.reward);
float gasprice = ((job->offer.total_distance/100.0f) * job->assigned_truck.fuelusage) * DIESEL_PRICE_PER_LITER;
@@ -1151,6 +1156,54 @@ static void end_contract_with_employee(world* world, employee* emp)
if (curr_loc) array_remove_by(&curr_loc->employees, &emp);
}
+static void world_update_location_scores(world* world)
+{
+ for (s32 i = 0; i < world->locations.length; i++)
+ {
+ world_location* location = array_at(&world->locations, i);
+ if (!location->is_owned) continue;
+
+ s32 total_scheduled_slots = 0;
+ for (int x = 0; x < location->schedule.jobs.length; x++)
+ {
+ scheduled_job* job = array_at(&location->schedule.jobs, x);
+ total_scheduled_slots += job->offer.shipday_count;
+ }
+
+ float total_happiness = 0.0f;
+ int total_employees_counted = 0;
+ for (s32 x = 0; x < location->employees.length; x++)
+ {
+ employee* em = *(employee**)array_at(&location->employees, x);
+ if (em->original_location_id != location->id) continue;
+
+ total_employees_counted++;
+ total_happiness += em->happiness;
+ }
+ if (total_employees_counted == 0) total_employees_counted = 1;
+
+ float total_trust = 0.0f;
+ int total_trust_counted = 0;
+ for (s32 x = 0; x < location->schedule.jobs.length; x++)
+ {
+ scheduled_job* scheduled_job = array_at(&location->schedule.jobs, x);
+ total_trust += scheduled_job->trust;
+ total_trust_counted++;
+ }
+ if (total_trust_counted == 0) total_trust_counted = 1;
+
+ float fill = total_scheduled_slots / ((float)TIME_SLOTS_PER_WEEK / 3);
+ if (fill > 1.0f) fill = 1.0f;
+
+ float happiness = total_happiness / total_employees_counted;
+ float trust = total_trust / total_trust_counted;
+ location->score = ((fill*3.0f)+(happiness*0.5f)+(trust*1.5f)) / 5.0f;
+
+ //printf("Score for location %s: (Schedule: %f Happiness: %f Trust: %f) = %f%% stars: %d\n",
+ // location->name, fill, happiness, trust, location->score*100.0f, (int)round(location->score * 5));
+ }
+}
+
static void world_run_simulation_tick(world* world)
{
s32 elapsed_sec = MINUTES(world->simulation_speed);
@@ -1195,6 +1248,7 @@ static void world_run_simulation_tick(world* world)
}
world_update_active_jobs(world);
+ world_update_location_scores(world);
}
void world_update(platform_window* window, world* world)