diff options
Diffstat (limited to 'src/scenes/place_detail.c')
| -rw-r--r-- | src/scenes/place_detail.c | 1771 |
1 files changed, 1771 insertions, 0 deletions
diff --git a/src/scenes/place_detail.c b/src/scenes/place_detail.c new file mode 100644 index 0000000..699fe0e --- /dev/null +++ b/src/scenes/place_detail.c @@ -0,0 +1,1771 @@ +typedef enum t_place_detail_state
+{
+ PLACE_DETAIL_SHOW_MAIN,
+ PLACE_DETAIL_SHOW_RESUMES,
+ PLACE_DETAIL_SHOW_DEALERS,
+ PLACE_DETAIL_SHOW_EMPLOYEE,
+ PLACE_DETAIL_SHOW_SCHEDULE,
+} place_detail_state;
+
+typedef enum t_place_detail_info_state
+{
+ PLACE_DETAIL_EMPLOYEES = 0,
+ PLACE_DETAIL_JOBOFFERS = 1,
+ PLACE_DETAIL_SCHEDULE = 2,
+ PLACE_DETAIL_GARAGE = 3,
+} place_detail_info_state;
+
+typedef enum t_schedule_state
+{
+ SCHEDULING_JOB,
+ RESCHEDULING_JOB,
+ VIEWING,
+} schedule_state;
+
+// Animations
+#define TAG_ANIMATION_DURATION 100
+#define EMPLOYEE_SELECTOR_ANIMATION_DURATION 100
+#define TRUCK_SWAP_ANIMATION_DURATION 200
+animation tag_animation = {0,0,0,1};
+animation employee_selector_animation = {0,0,0,1};
+animation truck_swap_animation = {0,0,0,1};
+
+// States
+world_location* _active_location;
+employee* _active_employee;
+scheduled_job _active_scheduling_job;
+scheduled_job* _active_selected_scheduled_job;
+schedule_state _active_schedule_state = VIEWING;
+s32 _active_schedule_selected_job_index = 0;
+place_detail_info_state selected_tab_index = PLACE_DETAIL_EMPLOYEES;
+place_detail_state current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+static s16 selected_truck_index = 0;
+static u8 active_dealer_index = 0;
+#define INVALID_VAL -999
+static s32 index_of_truck = INVALID_VAL;
+
+typedef struct t_tab
+{
+ s32 x;
+ s32 y;
+ s32 w;
+ s32 h;
+ float scale;
+} tab;
+
+void _goto_default_detail_state()
+{
+ index_of_truck = INVALID_VAL;
+ selected_truck_index = 0;
+ active_dealer_index = 0;
+ _active_employee = 0;
+ _active_schedule_state = VIEWING;
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+ _active_schedule_selected_job_index = 0;
+ _active_selected_scheduled_job = 0;
+ keyboard_set_input_text("");
+ _global_keyboard.take_input = false;
+}
+
+void place_detail_set_active_location(world_location* location)
+{
+ _active_location = location;
+ selected_tab_index = PLACE_DETAIL_EMPLOYEES;
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+}
+
+void place_detail_scene_init()
+{
+
+}
+
+static char* get_shipday_list_string(job_offer* offer, char* buf, s32 len)
+{
+ memset(buf, 0, len);
+ bool first = true;
+ if (job_offer_has_ship_day(offer, MONDAY)) { string_appendn(buf, "Mon", len); first = false; }
+ if (job_offer_has_ship_day(offer, TUESDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Tue", len); first = false; }
+ if (job_offer_has_ship_day(offer, WEDNESDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Wed", len); first = false; }
+ if (job_offer_has_ship_day(offer, THURSDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Thu", len); first = false; }
+ if (job_offer_has_ship_day(offer, FRIDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Fri", len); first = false; }
+ if (job_offer_has_ship_day(offer, SATURDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Sat", len); first = false; }
+ if (job_offer_has_ship_day(offer, SUNDAY)) { if (!first) string_appendn(buf, ", ", len); string_appendn(buf, "Sun", len); first = false; }
+
+ return buf;
+}
+
+static scheduled_job* get_scheduled_job_at_time(s32 day, s32 timeslot)
+{
+ for (s32 i = 0; i < _active_location->schedule.jobs.length; i++) {
+ scheduled_job* slot = array_at(&_active_location->schedule.jobs, i);
+ for (s32 x = 0; x < slot->offer.shipday_count; x++) {
+ if (slot->timeslots[x].day == day && slot->timeslots[x].timeslot == timeslot) return slot;
+ }
+ }
+ return 0;
+}
+
+static s32 find_empty_timeslot_for_day(s32 day)
+{
+ log_assert(day >= 0 && day < NUM_DAYS, "Invalid day");
+ for (s32 i = 0; i < TIME_SLOTS_PER_DAY; i++) {
+ scheduled_job* job = get_scheduled_job_at_time(day, i);
+ if (!job || (_active_schedule_state == RESCHEDULING_JOB && job == _active_selected_scheduled_job)) return i;
+ }
+ return -1;
+}
+
+static s32 find_empty_timeslot_for_day_right_to_left(s32 day)
+{
+ log_assert(day >= 0 && day < NUM_DAYS, "Invalid day");
+ for (s32 i = TIME_SLOTS_PER_DAY-1; i >= 0; i--) {
+ scheduled_job* job = get_scheduled_job_at_time(day, i);
+ if (!job || (_active_schedule_state == RESCHEDULING_JOB && job == _active_selected_scheduled_job)) return i;
+ }
+ return -1;
+}
+
+
+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;
+ for (s32 i = 0; i < MAX_SHIPDAYS; i++) {
+ new_job.timeslots[i] = (scheduled_job_time){-1, -1, 0, 0};
+ }
+ for (s32 i = 0; i < job->shipday_count; i++) {
+ new_job.timeslots[i] = (scheduled_job_time){job->shipdays[i], find_empty_timeslot_for_day(job->shipdays[i]), 0, 0};
+ }
+ return new_job;
+}
+
+#define scroll_speed 15
+#define HANDLE_TAB_SCROLL\
+ bool hovering_tab = (_global_mouse.y >= orig_y && _global_mouse.y <= orig_y + h \
+ && _global_mouse.x >= x && _global_mouse.x <= x + w);\
+ if (scroll_h > 0) {\
+ if (hovering_tab) {\
+ if (_global_mouse.scroll_state < 0) current_scroll += scroll_speed;\
+ if (_global_mouse.scroll_state > 0) current_scroll -= scroll_speed;\
+ }\
+ if (current_scroll > scroll_h) current_scroll = scroll_h;\
+ if (current_scroll < 0) current_scroll = 0;\
+ y -= current_scroll;\
+ }
+
+#define HANDLE_TAB_START(_count, _parts)\
+ s32 item_h = 34 * tab.scale;\
+ s32 total_h = (item_h+1) * (_count) + (10 * tab.scale);\
+ s32 scroll_h = total_h - h;\
+ s32 orig_y = y;\
+ static s32 current_scroll = 0;\
+ font* fnt = fnt_rd16;\
+ s32 info_text_h = fnt->px_h*4;\
+ scroll_h += info_text_h;\
+ s32 item_part_w = (w-item_h) / _parts;\
+ (void)item_part_w;
+
+#define HANDLE_TAB_INFO(_info, _btn_name, _next_state)\
+ s32 btn_h = info_text_h/1.3;\
+ s32 btn_w = btn_h*4;\
+ total_h += info_text_h;\
+ s32 info_text_y = y + (btn_h/2)-(fnt->px_h/2);\
+ renderer->render_text(fnt, x+1, info_text_y+1, _info, COLOR_TEXT_SHADOW);\
+ renderer->render_text(fnt, x, info_text_y, _info, COLOR_TEXT);\
+ if (_btn_name && button_render(tab.scale, true, _btn_name, x+w-btn_w-1, y, btn_w, btn_h)) {\
+ current_detail_state = _next_state;\
+ }\
+ y += info_text_h;
+
+#define HANDLE_TAB_ITEM_INTERACTION(_take) HANDLE_TAB_ITEM_INTERACTIONX(_take, i);
+#define HANDLE_TAB_ITEM_INTERACTIONX(_take, _count)\
+ s32 item_y = y + ((item_h+1) * _count);\
+ bool hovered = (_global_mouse.x >= x && _global_mouse.x <= x + w\
+ && _global_mouse.y >= item_y && _global_mouse.y <= item_y + item_h\
+ && hovering_tab);\
+ color tint = COLOR_LIST_ENTRY_BACKGROUND;\
+ if (_take && hovered) {\
+ tint = COLOR_LIST_ENTRY_BACKGROUND_ACTIVE;\
+ platform_set_cursor(window, CURSOR_POINTER);\
+ }\
+ renderer->render_rectangle(x, item_y, w, item_h, tint);
+
+#define TAB_ITEM_PUSH_TEXT(_buf,_width,_total)\
+ s32 text_w = renderer->calculate_text_width(fnt, _buf);\
+ s32 x_start = (x + item_h*2 - text_pad) + _total;\
+ s32 text_x = x_start + (_width/2)-(text_w/2);\
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);\
+ renderer->render_text(fnt, text_x+1, text_y+1, _buf, COLOR_TEXT_SHADOW);\
+ renderer->render_text(fnt, text_x, text_y,_buf, COLOR_TEXT);\
+ renderer->render_rectangle(x_start + _width, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);\
+ _total += _width;
+
+#define PUSH_NOT_AVAILABLE_TEXT(_cond, _text)\
+ if (_cond) {\
+ font* fnt = fnt_rd20;\
+ char* txt = _text;\
+ s32 textw = renderer->calculate_text_width(fnt, txt);\
+ renderer->render_text(fnt, x+(w/2)-(textw/2), y+(tab.h/2)-(fnt->px_h/2)-(30*scale), txt, COLOR_TEXT);\
+ }
+
+static void place_detail_draw_job_offers(platform_window* window, tab tab, float x, float y, float w, float h)
+{
+ HANDLE_TAB_START(_active_location->job_offers.length, 2);
+ HANDLE_TAB_SCROLL;
+
+ char info_buf[50];
+ sprintf(info_buf, "%d Job offers open.", _active_location->job_offers.length);
+ HANDLE_TAB_INFO(info_buf, 0, 0);
+
+ PUSH_NOT_AVAILABLE_TEXT(!_active_location->job_offers.length, "No job offers available.");
+
+ for (s32 i = 0; i < _active_location->job_offers.length; i++) {
+ job_offer* offer = array_at(&_active_location->job_offers, i);
+ HANDLE_TAB_ITEM_INTERACTION(true);
+
+ if (hovered && is_left_clicked()) {
+ current_detail_state = PLACE_DETAIL_SHOW_SCHEDULE;
+ _active_schedule_state = SCHEDULING_JOB;
+ _active_schedule_selected_job_index = 0;
+ _active_selected_scheduled_job = 0;
+ _active_scheduling_job = create_empty_job_schedule(offer);
+
+ tag_animation = animation_create(TAG_ANIMATION_DURATION);
+ tag_animation.started = true;
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ }
+
+ float icon_pad = item_h * 0.15;
+ float text_pad = icon_pad*2;
+ float icon_s = item_h - (icon_pad*2);
+ // icon
+ {
+ renderer->render_image(offer->company->logo, x + icon_pad, item_y + icon_pad, icon_s*2, icon_s);
+ renderer->render_rectangle(x + icon_pad + icon_s*2 + icon_pad, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+
+ float width_of_piece = 80 * tab.scale;
+ float price_text_w = 0;
+
+ // price
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "$%d/trip", offer->reward);
+ TAB_ITEM_PUSH_TEXT(pricebuf, width_of_piece, price_text_w);
+ }
+
+ // distance
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "%.0fkm", offer->total_distance);
+ TAB_ITEM_PUSH_TEXT(pricebuf, width_of_piece, price_text_w);
+ }
+
+ // dur
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "%.0fh-%.0fh", offer->duration_sec_min/3600.0f, offer->duration_sec_max/3600.0f);
+ TAB_ITEM_PUSH_TEXT(pricebuf, width_of_piece, price_text_w);
+ }
+
+ // Name
+ {
+ char daybuf[50];
+ char buf[200];
+ sprintf(buf, "%s wants you to ship %s to %s every %s", offer->company->name, offer->product->name,
+ (*(world_location**)array_at(&offer->connections, offer->connections.length-1))->name, get_shipday_list_string(offer, daybuf, 50));
+ s32 text_x = x + item_h*2 + price_text_w + icon_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buf, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buf, COLOR_TEXT);
+ }
+ }
+}
+
+
+static void place_detail_draw_trucks(platform_window* window, tab tab, float x, float y, float w, float h)
+{
+ HANDLE_TAB_START(_active_location->trucks.length, 5);
+ HANDLE_TAB_SCROLL;
+
+ char info_buf[50];
+ sprintf(info_buf, "%d Trucks in garage.", _active_location->trucks.length);
+ HANDLE_TAB_INFO(info_buf, "Purchase", PLACE_DETAIL_SHOW_DEALERS);
+
+ PUSH_NOT_AVAILABLE_TEXT(!_active_location->trucks.length, "No trucks in garage.");
+
+ for (s32 i = 0; i < _active_location->trucks.length; i++) {
+ truck* emp = array_at(&_active_location->trucks, i);
+ HANDLE_TAB_ITEM_INTERACTION(false);
+
+ float icon_pad = item_h * 0.15;
+ float text_pad = icon_pad*2;
+ float icon_s = item_h - (icon_pad*2);
+ // icon
+ {
+ renderer->render_image(emp->logo, x + icon_pad, item_y + icon_pad, icon_s, icon_s);
+ renderer->render_rectangle(x + icon_pad + icon_s + icon_pad, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // Name
+ {
+ char buffer[MAX_WORLD_LOCATION_NAME_LENGTH + 20];
+ sprintf(buffer, "%s, ID: #%d", emp->name, emp->id);
+
+ s32 text_x = x + item_h + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ renderer->render_rectangle(x + item_h + item_part_w, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // current location
+ {
+ char buffer[MAX_EMPLOYEE_NAME_LENGTH + 20];
+ if (emp->assigned_employee) sprintf(buffer, "Assigned to %s", emp->assigned_employee->name);
+ else strcpy(buffer, "No assignee");
+ s32 text_x = x + item_h + item_part_w*1 + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ }
+ }
+}
+
+static void place_detail_draw_employees(platform_window* window, tab tab, float x, float y, float w, float h)
+{
+ HANDLE_TAB_START(_active_location->employees.length+2, 4);
+ HANDLE_TAB_SCROLL;
+
+ char info_buf[50];
+ sprintf(info_buf, "%d Employees currently on site.", _active_location->employees.length);
+ HANDLE_TAB_INFO(info_buf, "Hire", PLACE_DETAIL_SHOW_RESUMES);
+
+ s32 current_index = 0;
+ bool show_internal = true;
+ do_again:;
+
+ for (s32 i = 0; i <= _active_location->employees.length; i++) {
+ employee* emp = 0;
+ if (i > 0) {
+ emp = *(employee**)array_at(&_active_location->employees, i-1);
+ bool is_internal = (emp->original_location_id == _active_location->id);
+ if (show_internal != is_internal) continue;
+ }
+
+ HANDLE_TAB_ITEM_INTERACTIONX(i != 0, current_index);
+ if (i != 0 && hovered && is_left_clicked()) {
+ place_detail_show_employee_detail(emp);
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ }
+ current_index++;
+
+ if (i == 0) {
+ char* buffer = show_internal ? "Internal" : "External";
+ s32 text_x = x + item_h;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ continue;
+ }
+
+ float icon_pad = item_h * 0.15;
+ float text_pad = icon_pad*2;
+ float icon_s = item_h - (icon_pad*2);
+ // icon
+ {
+ draw_employee_portrait(emp, x + icon_pad, item_y + icon_pad, icon_s, icon_s);
+ renderer->render_rectangle(x + icon_pad + icon_s + icon_pad, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // Name
+ {
+ char buffer[MAX_EMPLOYEE_NAME_LENGTH + 20];
+ sprintf(buffer, "%s, ID: #%d", emp->name, emp->id);
+ s32 text_x = x + item_h + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ renderer->render_rectangle(x + item_h + item_part_w, item_y+(5*tab.scale), 1, item_h-(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // Name
+ {
+ char buffer[MAX_EMPLOYEE_NAME_LENGTH + 20];
+ if (emp->assigned_truck) sprintf(buffer, "Truck: %s, #%d", emp->assigned_truck->name, emp->assigned_truck->id);
+ else strcpy(buffer, "No assigned truck");
+ s32 text_x = x + item_h + item_part_w*1 + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ renderer->render_rectangle(x + item_h + item_part_w*2, item_y+(5*tab.scale), 1, item_h-(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // current location
+ {
+ char buffer[MAX_WORLD_LOCATION_NAME_LENGTH + 20];
+ if (emp->active_job_id != INVALID_ID) {
+ active_job* j = get_active_job_by_id(_active_world, emp->active_job_id);
+ job_endpoints endpoints = job_offer_get_endpoints(&j->offer);
+ sprintf(buffer, "Driving to %s", endpoints.dest->name);
+ }
+ else if (emp->current_location_id != _active_location->id) { // employee located at other location
+ sprintf(buffer, "Located at %s", get_world_location_by_id(_active_world, emp->current_location_id)->name);
+ }
+ else { // At original location
+ sprintf(buffer, "%s", "Idling");
+ }
+
+ s32 text_x = x + item_h + item_part_w*2 + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, buffer, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buffer, COLOR_TEXT);
+ renderer->render_rectangle(x + item_h + item_part_w*3, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+
+ // Happiness
+ {
+ s32 text_x = x + item_h + item_part_w*3 + text_pad;
+ s32 text_y = item_y + (item_h/2) - (fnt->px_h/2);
+
+ s32 stars = employee_calculate_happiness_stars(emp);
+ s32 textw = renderer->render_text(fnt, text_x, text_y, "Happiness: ", COLOR_TEXT);
+ text_x += (scale*5);
+ for (s32 i = 0; i < 5; i++)
+ {
+ if (i < stars) renderer->render_image(img_star, text_x + textw + (i*(fnt->px_h+2)), text_y, fnt->px_h, fnt->px_h);
+ else renderer->render_image_tint(img_star, text_x + textw + (i*(fnt->px_h+2)), text_y, fnt->px_h, fnt->px_h, rgba(255,255,255,30));
+ }
+
+ //renderer->render_rectangle(x + item_h + item_part_w*4, item_y+(5*tab.scale), 1, item_h-+(10*tab.scale), COLOR_BUTTON);
+ }
+ }
+
+ if (show_internal) {
+ show_internal = false;
+ goto do_again;
+ }
+}
+
+static void render_logo_at(image* img, s32 pad, s32 x, s32 y, s32 w, s32 h)
+{
+ if (img->width >= img->height)
+ {
+ float s_scale = w/(float)img->width;
+ float new_w = w - (pad*2);
+ float new_h = (img->height * s_scale) - (pad*2);
+ float new_x = x + w/2 - new_w/2;
+ float new_y = y + h/2 - new_h/2;
+ renderer->render_image(img,new_x,new_y,new_w,new_h);
+ }
+}
+
+static void place_detail_draw_active_dealer(platform_window* window, truck_dealer* dealer, float scale, s32 x, s32 y, s32 w, s32 h)
+{
+ button_render(scale, false, 0, x, y, w, h);
+ static truck_dealer* prev_dealer = 0;
+ if (prev_dealer != dealer) {
+ prev_dealer = dealer;
+ selected_truck_index = 0;
+ }
+
+ if (selected_truck_index < 0) selected_truck_index = 0;
+ if (selected_truck_index >= dealer->trucks.length) selected_truck_index = dealer->trucks.length-1;
+ truck* tr_curr = (selected_truck_index >= 0 && selected_truck_index <= dealer->trucks.length-1) ? array_at(&dealer->trucks, selected_truck_index) : 0;
+ truck* tr_prev = (selected_truck_index-1 >= 0) ? array_at(&dealer->trucks, selected_truck_index-1) : 0;
+ truck* tr_next = (selected_truck_index+1 <= dealer->trucks.length-1) ? array_at(&dealer->trucks, selected_truck_index+1) : 0;
+ if (!tr_curr) return;
+ s32 total_img_space = (w)/3 * 2;
+ s32 img_w_center = total_img_space/10*5;
+ s32 img_w_side = total_img_space/10*2.5;
+ s32 pad = 40 * scale;
+ s32 img_x = x;
+ s32 img_y = y;
+
+ static animation swap_animation = {0,0,0,0};
+ static animation purchase_animation = {0,0,0,0};
+ if (swap_animation.started) animation_update(&swap_animation);
+ if (purchase_animation.started) animation_update(&purchase_animation);
+ static s32 target_truck_index = 0;
+
+ truck* tn_prev = (target_truck_index-1 >= 0) ? array_at(&dealer->trucks, target_truck_index-1) : 0;
+ truck* tn_next = (target_truck_index+1 <= dealer->trucks.length-1) ? array_at(&dealer->trucks, target_truck_index+1) : 0;
+
+ // Truck images
+ {
+ s32 overlap = 50 * scale;
+
+ s32 y_side = img_y + (h / 2) - (img_w_side/2);
+ s32 x_left = img_x + overlap;
+ s32 y_left = y_side;
+ s32 w_left = img_w_side;
+ s32 h_left = img_w_side;
+
+ s32 x_right = img_x+img_w_side+img_w_center - overlap;
+ s32 y_right = y_side;
+ s32 w_right = img_w_side;
+ s32 h_right = img_w_side;
+
+ s32 x_center = img_x+img_w_side;
+ s32 y_center = img_y + (h / 2) - (img_w_center/2);
+ s32 w_center = img_w_center;
+ s32 h_center = img_w_center;
+
+ #define LI(_cx,_dx) (_cx + (_dx-_cx)*swap_animation.percentage)
+ #define LIP(_cx,_dx) (_cx + (_dx-_cx)*purchase_animation.percentage)
+ #define LI_TINT(_c,_d) rgba(255,255,255,_c + (_d-_c)*swap_animation.percentage)
+ #define LI_TINTP(_c,_d) rgba(255,255,255,_c + (_d-_c)*purchase_animation.percentage)
+
+ if (tr_prev) {
+ if (target_truck_index < selected_truck_index) {
+ color tint = LI_TINT(50, 255);
+ renderer->render_image_tint(tr_prev->logo,LI(x_left,x_center),LI(y_left,y_center),LI(w_left,w_center),LI(h_left,h_center), tint);
+
+ if (swap_animation.started && tn_prev) {
+ color tint = LI_TINT(0, 50);
+ renderer->render_image_tint(tn_prev->logo,x_left,y_left,w_left,h_left, tint);
+ }
+ }
+ else {
+ color tint = LI_TINT(50, 0);
+ renderer->render_image_tint(tr_prev->logo,x_left,y_left,w_left,h_left, tint);
+ }
+ }
+ if (tr_next) {
+ if (target_truck_index < selected_truck_index) {
+ color tint = LI_TINT(50, 0);
+ renderer->render_image_tint(tr_next->logo,x_right,y_right,w_right,h_right, tint);
+ }
+ else {
+ color tint = LI_TINT(50, 255);
+ renderer->render_image_tint(tr_next->logo,LI(x_right,x_center),LI(y_right,y_center),LI(w_right,w_center),LI(h_right,h_center), tint);
+
+ if (swap_animation.started && tn_next) {
+ color tint = LI_TINT(0, 50);
+ renderer->render_image_tint(tn_next->logo,x_right,y_right,w_right,h_right, tint);
+ }
+ }
+ }
+ if (!purchase_animation.started)
+ {
+ color tint = LI_TINT(255, 50);
+ if (target_truck_index < selected_truck_index)
+ renderer->render_image_tint(tr_curr->logo,LI(x_center,x_right),LI(y_center,y_right),LI(w_center,w_right),LI(h_center,h_right), tint);
+ else
+ renderer->render_image_tint(tr_curr->logo,LI(x_center,x_left),LI(y_center,y_left),LI(w_center,w_left),LI(h_center,h_left), tint);
+ }
+ else {
+ vec4 area = camera_get_target_rectangle(window);
+ s32 x_off = area.x;
+ s32 h_off = area.h/2;
+ s32 y_off = area.y+(area.h/2)-(h_off/2);
+ s32 w_off = h_off;
+
+ color tint = LI_TINTP(255, 0);
+ renderer->render_image_tint(tr_curr->logo,LIP(x_center,x_off),LIP(y_center,y_off),LIP(w_center,w_off),LIP(h_center,h_off), tint);
+ }
+ }
+
+ font* fnt = fnt_rd24;
+ s32 text_y = img_y + pad;
+ s32 text_x = x + total_img_space;
+
+ #define PUSH_TEXT(_str, _data)\
+ {char buf[50]; snprintf(buf,50,_str,_data);\
+ renderer->render_text(fnt, text_x+1, text_y+1, buf, COLOR_TEXT_SHADOW);\
+ renderer->render_text(fnt, text_x, text_y, buf, COLOR_TEXT);}\
+ text_y+=fnt->px_h+(10*scale);
+
+ PUSH_TEXT("Name: %s", tr_curr->name);
+ PUSH_TEXT("Power: %dhp", tr_curr->hp);
+ PUSH_TEXT("Price: $%d", tr_curr->price);
+ PUSH_TEXT("Fuel Capacity: %dL", tr_curr->fuelcapacity);
+ PUSH_TEXT("Torque %drpm", tr_curr->torque);
+ PUSH_TEXT("Fuel Usage %.1fL per 100Km", tr_curr->fuelusage);
+
+ #define TRUCK_SWAP_DELAY 200
+ #define TRUCK_PURCHASE_DELAY 800
+ s32 btn_size = 30*scale;
+ s32 btn_x = text_x;
+
+ button_type type1 = purchase_animation.started || swap_animation.started ? BUTTON_STATIC : (selected_truck_index > 0) ? BUTTON_ENABLED : BUTTON_DISABLED;
+ if (button_render(scale, type1, "<", btn_x, text_y, btn_size, btn_size)) {
+ if (!swap_animation.started) {
+ swap_animation = animation_create(TRUCK_SWAP_DELAY);
+ swap_animation.started = true;
+ target_truck_index = selected_truck_index-1;
+ }
+ }
+ btn_x += btn_size;
+ s32 center_btn_w = 100*scale;
+ button_type type2 = purchase_animation.started || swap_animation.started ? BUTTON_STATIC : BUTTON_ENABLED;
+ if (button_render(scale, type2, "purchase", btn_x, text_y, center_btn_w, btn_size)) {
+ ADD_EXPENSE(_active_world, _active_location, expenses_from_trucks, tr_curr->price)
+ add_truck_to_world_location(_active_world, _active_location, tr_curr);
+ purchase_animation = animation_create(TRUCK_PURCHASE_DELAY);
+ purchase_animation.started = true;
+ }
+ btn_x += center_btn_w;
+ button_type type3 = purchase_animation.started || swap_animation.started ? BUTTON_STATIC : (selected_truck_index < dealer->trucks.length-1) ? BUTTON_ENABLED : BUTTON_DISABLED;
+ if (button_render(scale, type3, ">", btn_x, text_y, btn_size, btn_size)) {
+ if (!swap_animation.started) {
+ swap_animation = animation_create(TRUCK_SWAP_DELAY);
+ swap_animation.started = true;
+ target_truck_index = selected_truck_index+1;
+ }
+ }
+ if (swap_animation.percentage == 1.0f) {
+ swap_animation = (animation){0,0,0,0};
+ selected_truck_index = target_truck_index;
+ }
+ if (purchase_animation.percentage == 1.0f) {
+ purchase_animation = (animation){0,0,0,0};
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+ selected_truck_index = 0;
+ active_dealer_index = 0;
+ }
+}
+
+void place_detail_show_schedule_with_highlighted_job(world_location* loc, scheduled_job* job, scheduled_job_time job_time) {
+ _goto_default_detail_state();
+ place_detail_set_active_location(loc);
+ game_set_active_scene(GAME_STATE_PLACE_DETAIL);
+
+ if (job) {
+ for (s32 i = 0; i < MAX_SHIPDAYS; i++) {
+ if (job_time.day == job->timeslots[i].day) {
+ _active_schedule_selected_job_index = i;
+ break;
+ }
+ }
+ }
+
+ _active_schedule_state = VIEWING;
+ _active_selected_scheduled_job = job;
+ selected_tab_index = PLACE_DETAIL_SHOW_MAIN;
+ current_detail_state = PLACE_DETAIL_SHOW_SCHEDULE;
+ tag_animation = animation_create(TAG_ANIMATION_DURATION);
+ tag_animation.started = true;
+}
+
+void place_detail_show_employee_detail(employee* emp) {
+ _goto_default_detail_state();
+ world_location* original_loc = get_world_location_by_id(_active_world, emp->original_location_id);
+ place_detail_set_active_location(original_loc);
+ game_set_active_scene(GAME_STATE_PLACE_DETAIL);
+ current_detail_state = PLACE_DETAIL_SHOW_EMPLOYEE;
+ _active_employee = emp;
+ tag_animation = animation_create(TAG_ANIMATION_DURATION);
+ tag_animation.started = true;
+}
+
+static s32 place_detail_draw_selected_employee_truck_selector(platform_window* window, s32 x, s32 y, s32 w, s32 h)
+{
+ s32 btn_w = 40*scale;
+ s32 pad = 30*scale;
+ s32 truck_h = h / 2;
+ s32 truck_w = truck_h;
+ s32 truck_x = x + (pad*2) + btn_w;
+ s32 truck_y = y + pad;
+
+ world_location* original_location = get_world_location_by_id(_active_world, _active_employee->original_location_id);
+
+ if (index_of_truck == INVALID_VAL) {
+ index_of_truck = _active_employee->assigned_truck ? ((void*)_active_employee->assigned_truck - (void*)original_location->trucks.data) / sizeof(truck) : -1;
+ }
+
+ s32 bg_h = h;
+ s32 bg_w = truck_w + (btn_w*2) + (pad*4);
+ button_draw_background(scale, x,y,bg_w,bg_h, COLOR_WHITE, COLOR_BUTTON);
+
+ static bool animation_going_left = false;
+
+ // Draw truck info
+ {
+ #define TRUCK_ANIMATION_OFFSET (animation_going_left ? -60*scale : 60*scale)
+ s32 truck_offset_x = TRUCK_ANIMATION_OFFSET - (TRUCK_ANIMATION_OFFSET*truck_swap_animation.percentage);
+ color truck_tint = AN_LI_TINT(COLOR_WHITE, truck_swap_animation);
+
+ truck* selected_truck = 0;
+ if (index_of_truck != -1) selected_truck = array_at(&original_location->trucks, index_of_truck);
+ renderer->render_image_tint(selected_truck ? selected_truck->logo : img_truck_unknown, truck_x+truck_offset_x, truck_y, truck_w, truck_h, truck_tint);
+ if (selected_truck) {
+ font* fnt = fnt_rd24;
+ char buf[40];
+ sprintf(buf, "%s, ID: #%d", selected_truck->name, selected_truck->id);
+ s32 text_w = renderer->calculate_text_width(fnt, buf);
+ s32 text_x = truck_x + (truck_w/2)-(text_w/2);
+ renderer->render_text(fnt, text_x+1+truck_offset_x, truck_y+truck_h+1, buf, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x+truck_offset_x,truck_y+truck_h, buf, COLOR_TEXT);
+ }
+ }
+
+ // Change truck
+ {
+ if (button_render(scale, BUTTON_ENABLED, "<", truck_x-btn_w-pad,truck_y, btn_w, truck_h)) {
+ s32 prev_index = index_of_truck;
+ index_of_truck = -1;
+
+ try_again:
+ for (s32 i = prev_index-1; i >= 0; i--) {
+ truck* emp = array_at(&original_location->trucks, i);
+ if (emp->assigned_employee == 0 || emp->assigned_employee == _active_employee) {
+ index_of_truck = i;
+ break;
+ }
+ }
+
+ if (prev_index == -1) {
+ prev_index = original_location->trucks.length;
+ goto try_again;
+ }
+
+ truck_swap_animation = animation_create(TRUCK_SWAP_ANIMATION_DURATION);
+ truck_swap_animation.started = true;
+ animation_going_left = true;
+ }
+ if (button_render(scale, BUTTON_ENABLED, ">", truck_x+truck_w+pad,truck_y, btn_w, truck_h)) {
+ s32 prev_index = index_of_truck;
+ index_of_truck = -1;
+ for (s32 i = prev_index+1; i < original_location->trucks.length; i++) {
+ truck* emp = array_at(&original_location->trucks, i);
+ if (emp->assigned_employee == 0 || emp->assigned_employee == _active_employee) {
+ index_of_truck = i;
+ break;
+ }
+ }
+
+ truck_swap_animation = animation_create(TRUCK_SWAP_ANIMATION_DURATION);
+ truck_swap_animation.started = true;
+ animation_going_left = false;
+ }
+ }
+
+
+ // Save changes button
+ {
+ s32 btn_h = 30*scale;
+ btn_w = 160*scale;
+ s32 btn_y = y + h - pad - btn_h;
+ s32 btn_x = x + (bg_w/2) - (btn_w/2);
+ if (button_render(scale, BUTTON_ENABLED, "Save Changes", btn_x, btn_y, btn_w, btn_h)) {
+ if (index_of_truck != -1) {
+ if (_active_employee->assigned_truck) _active_employee->assigned_truck->assigned_employee = 0;
+ _active_employee->assigned_truck = array_at(&_active_location->trucks, index_of_truck);
+ log_assert(_active_employee->assigned_truck->assigned_employee == 0 &&
+ _active_employee->assigned_truck->assigned_employee != _active_employee, "Truck already has assignee");
+
+ _active_employee->assigned_truck->assigned_employee = _active_employee;
+ }
+ else {
+ if (_active_employee->assigned_truck) _active_employee->assigned_truck->assigned_employee = 0;
+ _active_employee->assigned_truck = 0;
+ }
+
+ index_of_truck = INVALID_VAL;
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+ }
+ }
+
+ animation_update(&truck_swap_animation);
+ return bg_w;
+}
+
+static void place_detail_draw_selected_employee(platform_window* window)
+{
+ float offset = scale * 40.0;
+ s32 item_h = 82 * 0.4 * scale;
+ s32 h = (area.h * 0.6 - (offset*2)) + item_h;
+ s32 w = (area.w * 0.9 - (offset*2));
+ s32 x = offset + area.x + (area.w*0.05);
+ s32 pos_y = area.y + (area.w*0.12);
+ s32 y = pos_y;
+
+ s32 truck_selector_w = place_detail_draw_selected_employee_truck_selector(window, x, y, w, h);
+
+ {
+ font* fnt = fnt_rd24;
+
+ s32 info_panel_x = x + truck_selector_w+offset;
+ s32 info_panel_w = w - offset - truck_selector_w;
+ s32 pad = 30*scale;
+
+ s32 text_y = y + pad;
+ s32 text_x = info_panel_x + pad;
+ s32 text_offset = fnt->px_h + (10*scale);
+ s32 info_h = (h/2)-(pad/2);
+ button_draw_background(scale, info_panel_x, y, info_panel_w, info_h, COLOR_WHITE, COLOR_BUTTON);
+
+ s32 portrait_h = (info_h)-(pad*2);
+ draw_employee_portrait(_active_employee, text_x, text_y, portrait_h, portrait_h);
+
+ text_x += portrait_h + pad;
+
+ #define PUSH_INFO_TEXT(_fmt, _data)\
+ {\
+ char buf[100];\
+ sprintf(buf, _fmt, _data);\
+ renderer->render_text(fnt, text_x, text_y, buf, COLOR_TEXT);\
+ text_y += text_offset;\
+ }
+
+ PUSH_INFO_TEXT("Name: %s", _active_employee->name);
+ PUSH_INFO_TEXT("Age: %d", _active_employee->age);
+ PUSH_INFO_TEXT("Experience: %d years", _active_employee->experience);
+ PUSH_INFO_TEXT("Salary: $%.2f/month", _active_employee->salary);
+
+ // Happiness
+ {
+ s32 stars = employee_calculate_happiness_stars(_active_employee);
+ s32 textw = renderer->render_text(fnt, text_x, text_y, "Happiness: ", COLOR_TEXT);
+ for (s32 i = 0; i < 5; i++)
+ {
+ if (i < stars) renderer->render_image(img_star, text_x + textw + (i*(fnt->px_h+2)), text_y, fnt->px_h, fnt->px_h);
+ else renderer->render_image_tint(img_star, text_x + textw + (i*(fnt->px_h+2)), text_y, fnt->px_h, fnt->px_h, rgba(255,255,255,30));
+ }
+ text_y += text_offset;
+ }
+
+ #define SALARY_RAISE_INCREASE 70
+ // Buttons
+ {
+ s32 pad_between_items = 10 * scale;
+ s32 button_w = 164 * scale;
+ s32 button_h = 37 * scale;
+ s32 btn_y = y+info_h+pad+info_h-button_h;
+ s32 btn_x = x + w - button_w;
+ if (button_render(scale, BUTTON_ENABLED, "End Contract", btn_x, btn_y, button_w, button_h)) {
+ audio_play_sound(snd_click3, AUDIO_CHANNEL_SFX_1);
+ end_contract_with_employee(_active_world, _active_employee);
+ _active_employee = 0;
+ _goto_default_detail_state();
+ }
+ btn_y -= (button_h+pad_between_items);
+
+ if (button_render(scale, BUTTON_ENABLED, "Give Raise", btn_x, btn_y, button_w, button_h)) {
+ audio_play_sound(snd_click2, AUDIO_CHANNEL_SFX_1);
+ _active_employee->salary += SALARY_RAISE_INCREASE;
+ }
+ btn_y -= (button_h+pad_between_items);
+ }
+ }
+}
+
+static void place_detail_draw_schedule_employee_options(platform_window* window, s32 pad, float scale, s32 x, s32 y, s32 w, s32 h)
+{
+ bool viewing = (_active_schedule_state == VIEWING && !_active_selected_scheduled_job);
+ if (viewing) return;
+
+ job_endpoints endpoints = job_offer_get_endpoints(&_active_scheduling_job.offer);
+ bool enabled = endpoints.dest->is_owned;
+
+ if (enabled) button_draw_background(scale, x,y,w,h, COLOR_WHITE, COLOR_BUTTON);
+ else button_draw_background(scale, x,y,w,h, COLOR_BUTTON_DISABLED_TINT, COLOR_BUTTON_DISABLED);
+
+ s32 checkbox_s = h/3;
+ scheduled_job_time selected_timeslot = _active_scheduling_job.timeslots[_active_schedule_selected_job_index];
+ if (_active_schedule_state == VIEWING) selected_timeslot = _active_selected_scheduled_job->timeslots[_active_schedule_selected_job_index];
+
+ char* check_txt = selected_timeslot.stay_at_destination ? "X" : "";
+ if (button_render(scale, enabled && _active_schedule_state != VIEWING ? BUTTON_ENABLED : BUTTON_DISABLED, check_txt, x+pad,y+(h/2)-(checkbox_s/2),checkbox_s,checkbox_s)) {
+ _active_scheduling_job.timeslots[_active_schedule_selected_job_index].stay_at_destination = !selected_timeslot.stay_at_destination;
+ }
+
+ font* fnt = fnt_rd20;
+ s32 textx = x + pad + checkbox_s + pad/2;
+ s32 texty = y+(h/2)-(fnt->px_h/2);
+ renderer->render_text(fnt, textx, texty, "Stay at destination", COLOR_TEXT);
+
+ if (!enabled) {
+ s32 icon_s = h/2;
+ renderer->render_image(img_lock, x + (w/2)-(icon_s/2), y + (h/2)-(icon_s/2), icon_s, icon_s);
+ }
+}
+
+static void place_detail_draw_schedule_employee_selector(platform_window* window, s32 pad, float scale, s32 x, s32 y, s32 w, s32 h)
+{
+ if (_active_schedule_state == VIEWING && !_active_selected_scheduled_job) {
+ button_render(scale, BUTTON_STATIC, 0, x,y,w,h);
+ font* fnt = fnt_rd20;
+ s32 texty = y + (h/2)-(fnt->px_h/2);
+ s32 textx = x + pad;
+ renderer->render_text(fnt, textx, texty, "Select a timeslot for details.", COLOR_TEXT);
+ }
+ else {
+ scheduled_job_time selected_timeslot = _active_scheduling_job.timeslots[_active_schedule_selected_job_index];
+
+ employee* selected_employee = selected_timeslot.assignee;
+ bool is_viewing_existing_timeslot = _active_selected_scheduled_job && _active_schedule_state == VIEWING;
+ if (is_viewing_existing_timeslot) {
+ selected_employee = _active_selected_scheduled_job->timeslots[_active_schedule_selected_job_index].assignee;
+ }
+
+ // When timeslot changes, set selected employee id as keyboard input text.
+ static s32 prev_selected_job_index = 0;
+ if (is_viewing_existing_timeslot) prev_selected_job_index = -1;
+ if (prev_selected_job_index != _active_schedule_selected_job_index) {
+ prev_selected_job_index = _active_schedule_selected_job_index;
+ if (selected_employee) {
+ char idbuf[20];
+ sprintf(idbuf, "%d", selected_employee->id);
+ keyboard_set_input_text(idbuf);
+ }
+ else {
+ keyboard_set_input_text("");
+ }
+ }
+
+ _active_scheduling_job.timeslots[_active_schedule_selected_job_index].assignee =
+ employee_selector_render(window, scale, !is_viewing_existing_timeslot, selected_employee,x,y,w,h, employee_selector_animation, &_active_scheduling_job);
+ animation_update(&employee_selector_animation);
+ }
+}
+
+static bool scheduling_job_is_correct()
+{
+ for (s32 i = 0; i < _active_scheduling_job.offer.shipday_count; i++) {
+ scheduled_job_time scheduled_time = _active_scheduling_job.timeslots[i];
+ if (!scheduled_time.assignee) { return false; }
+ if (scheduled_time.timeslot == -1) { return false; }
+ }
+ return true;
+}
+
+static void draw_duration_of_scheduled_job_entry(scheduled_job_time scheduled_time, s32 hour_w, s32 tx, s32 ty, s32 timeslot_w, s32 x, s32 y, s32 timeslot_h, color tile_color)
+{
+ #define TILE_X(_x) (x+hour_w+(timeslot_w*_x)+1)
+ #define TILE_Y(_y) (y+(timeslot_h*(CDAYTORDAY(_y)))+1)
+
+ s32 duration_of_job_measured_in_timeslots_max = ceil((_active_scheduling_job.offer.duration_sec_max/60.0f) / (60.0f/TIME_SLOTS_PER_HOUR));
+ if (!scheduled_time.stay_at_destination) duration_of_job_measured_in_timeslots_max*=2;
+ log_assert(duration_of_job_measured_in_timeslots_max < 36*TIME_SLOTS_PER_HOUR, "Multi-day trip not supported yet in schedule preview.");
+
+ s32 slots_outside_of_schedule = (24-(WORK_HOUR_END-WORK_HOUR_START))*TIME_SLOTS_PER_HOUR;
+ s32 overflow_to_next_day = -(((TIME_SLOTS_PER_DAY-scheduled_time.timeslot) -
+ (duration_of_job_measured_in_timeslots_max)) +
+ slots_outside_of_schedule);
+ color tile_color_bg = tile_color;
+ tile_color_bg.a = 50;
+
+ s32 highlight_w = timeslot_w*duration_of_job_measured_in_timeslots_max;
+ if (tx+highlight_w > x+(timeslot_w*(TIME_SLOTS_PER_DAY+TIME_SLOTS_PER_HOUR)))
+ highlight_w -= (tx+highlight_w) - (x+(timeslot_w*(TIME_SLOTS_PER_DAY+TIME_SLOTS_PER_HOUR)));
+ renderer->render_rectangle(tx, ty, highlight_w, timeslot_h, tile_color_bg);
+ s32 highlight_y = ty+timeslot_h;
+ if (scheduled_time.day == SUNDAY) highlight_y = TILE_Y(MONDAY);
+ if (overflow_to_next_day > 0) renderer->render_rectangle(TILE_X(0), highlight_y, timeslot_w*overflow_to_next_day, timeslot_h, tile_color_bg);
+}
+
+static void place_detail_draw_schedule(platform_window* window)
+{
+ float offset = scale * 40.0;
+ s32 item_h = 82 * 0.4 * scale;
+ s32 h = (area.h * 0.6 - (offset*2)) + item_h;
+ s32 pad_between_items = 10 * scale;
+ s32 employee_select_h = (h/4);
+ h -= employee_select_h + pad_between_items;
+ s32 w = (area.w * 0.9 - (offset*2));
+ s32 x = offset + area.x + (area.w*0.05);
+ s32 pos_y = area.y + (area.w*0.12);
+ s32 y = pos_y;
+ s32 btn_pad = pad_between_items/2;
+
+ s32 button_w = 124 * scale;
+ s32 button_h = (employee_select_h-btn_pad)/2;
+ s32 schedule_pad = 20*scale;
+
+ #define COLS (TIME_SLOTS_PER_DAY+TIME_SLOTS_PER_HOUR)
+ #define ROWS 8
+ s32 timeslot_w = (w-schedule_pad*2)/COLS;
+ s32 timeslot_h = (h-schedule_pad*2)/ROWS;
+ s32 hour_w = timeslot_w*4;
+ s32 new_w = (timeslot_w)*COLS+schedule_pad*2;
+ s32 new_h = (timeslot_h)*ROWS+schedule_pad*2;
+ s32 off_x = w - new_w;
+ s32 off_y = h - new_h;
+ w = new_w;
+ h = new_h;
+ x += off_x/2;
+ y += off_y/2;
+
+ s32 employee_select_y = y + h + pad_between_items;
+ s32 btn_y = y+h+pad_between_items;
+ if (_active_schedule_state == SCHEDULING_JOB || _active_schedule_state == RESCHEDULING_JOB)
+ {
+ button_type type = scheduling_job_is_correct() ? BUTTON_ENABLED : BUTTON_DISABLED;
+ if (button_render(scale, type, "Accept", x-button_w+w, btn_y, button_w, button_h)) {
+ audio_play_sound(snd_click2, AUDIO_CHANNEL_SFX_1);
+ if (_active_schedule_state == SCHEDULING_JOB)
+ array_push(&_active_location->schedule.jobs, &_active_scheduling_job);
+ else if (_active_schedule_state == RESCHEDULING_JOB)
+ *_active_selected_scheduled_job = _active_scheduling_job;
+
+ job_offer* offer = get_job_offer_by_id(_active_location, _active_scheduling_job.offer.id);
+ if (offer) array_remove_by(&_active_location->job_offers, offer);
+
+ _goto_default_detail_state();
+ }
+ btn_y += btn_pad + button_h;
+ if (button_render(scale, BUTTON_ENABLED, "Cancel", x-button_w+w, btn_y, button_w, button_h)) {
+ _goto_default_detail_state();
+ }
+ }
+ else if (_active_schedule_state == VIEWING && _active_selected_scheduled_job) {
+ if (button_render(scale, BUTTON_ENABLED, "Reschedule", x-button_w+w, btn_y, button_w, button_h)) {
+ _active_schedule_state = RESCHEDULING_JOB;
+ _active_scheduling_job = *_active_selected_scheduled_job;
+ }
+ }
+
+ s32 options_w = 230*scale;
+ s32 selector_w = w-options_w-(pad_between_items*2)-button_w;
+
+ button_render(scale, BUTTON_STATIC, 0, x,y,w,h);
+
+ x+=schedule_pad;
+ y+=schedule_pad;
+ w-=schedule_pad*2;
+ h-=schedule_pad*2;
+
+ #define TILE_X(_x) (x+hour_w+(timeslot_w*_x)+1)
+ #define TILE_Y(_y) (y+(timeslot_h*(CDAYTORDAY(_y)))+1)
+
+
+ vec2f hovered_tile = (vec2f){(s32)((_global_mouse.x-x)/timeslot_w)-TIME_SLOTS_PER_HOUR, (s32)((_global_mouse.y-y)/timeslot_h)};
+ s32 hovered_day = RDAYTOCDAY((s32)hovered_tile.y);
+ scheduled_job* existing_job_at_hovered_tile = get_scheduled_job_at_time(hovered_day, (s32)hovered_tile.x);
+ font* fnt = fnt_rd24;
+
+ static bool dragging_tile = false;
+
+ // newly scheduling job
+ if (_active_schedule_state == SCHEDULING_JOB || _active_schedule_state == RESCHEDULING_JOB)
+ {
+ for (s32 i = 0; i < _active_scheduling_job.offer.shipday_count; i++) {
+ scheduled_job_time scheduled_time = _active_scheduling_job.timeslots[i];
+ s32 dday = CDAYTORDAY(scheduled_time.day);
+ renderer->render_rectangle(x+hour_w, y+(dday*timeslot_h), w-hour_w, timeslot_h, COLOR_SCHEDULE_ROW_ACTIVE);
+
+ bool being_hovered = false;
+ bool valid_tile = (!existing_job_at_hovered_tile || (_active_schedule_state == RESCHEDULING_JOB && existing_job_at_hovered_tile == _active_selected_scheduled_job));
+ if (valid_tile && hovered_tile.x >= 0 && hovered_tile.x < TIME_SLOTS_PER_DAY && hovered_tile.y == dday) { // If in current row.
+
+ // Interaction.
+ if (_active_scheduling_job.timeslots[i].timeslot == hovered_tile.x) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ being_hovered = true;
+
+ // Check if player started to drag.
+ if (is_left_clicked_peak()) { // is_left_clicked_peak instead of is_left_clicked so employee selector can reset input.
+ dragging_tile = true;
+ _active_schedule_selected_job_index = i;
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ }
+ }
+ }
+
+ s32 tx = TILE_X(scheduled_time.timeslot);
+ s32 ty = TILE_Y(scheduled_time.day);
+
+ bool is_dragging_current_tile = (dragging_tile && _active_schedule_selected_job_index == i);
+ color tile_color = (_active_schedule_selected_job_index == i) ? COLOR_SCHEDULE_TILE_HOVERED : COLOR_SCHEDULE_TILE_SELECTED;
+
+ // Handle dragging.
+ if (being_hovered || is_dragging_current_tile) {
+
+ // Get index of new timeslot.
+ s32 index_to_set = hovered_tile.x;
+ s32 possible_tile_left = find_empty_timeslot_for_day(scheduled_time.day);
+ s32 possible_tile_right = find_empty_timeslot_for_day_right_to_left(scheduled_time.day);
+ if (index_to_set < 0) index_to_set = possible_tile_left;
+ if (index_to_set >= TIME_SLOTS_PER_DAY) index_to_set = possible_tile_right;
+
+ // Set new timeslot.
+ if (is_dragging_current_tile) {
+ platform_set_cursor(window, CURSOR_DRAG);
+
+ scheduled_job* existing_job_at_tile = get_scheduled_job_at_time(scheduled_time.day, index_to_set);
+ if (existing_job_at_tile == _active_selected_scheduled_job) existing_job_at_tile = 0; // Make sure reschedule can be set at current location.
+ if (index_to_set != -1 && !existing_job_at_tile) _active_scheduling_job.timeslots[i].timeslot = index_to_set;
+
+ if (!is_left_down()) {
+ dragging_tile = false;
+ }
+
+ tx = TILE_X(_active_scheduling_job.timeslots[i].timeslot);
+ ty = TILE_Y(scheduled_time.day);
+ }
+
+ // Draw duration of job.
+ draw_duration_of_scheduled_job_entry(scheduled_time, hour_w, tx, ty, timeslot_w, x, y, timeslot_h, tile_color);
+
+ // Draw left and right arrow.
+ s32 icon_s = timeslot_w*0.7f;
+ s32 icon_y = ty + (timeslot_h-icon_s)/2;
+ s32 icon_pad = (3*scale);
+ if (possible_tile_left != -1 && possible_tile_left != index_to_set) {
+ renderer->render_image_tint(img_arrow_left_rounded, tx - icon_s - icon_pad-1, icon_y, icon_s+2, icon_s,COLOR_SCHEDULE_BORDER_THIN);
+ renderer->render_image_tint(img_arrow_left_rounded, tx - icon_s - icon_pad, icon_y, icon_s, icon_s,tile_color);
+ }
+ if (possible_tile_right != -1 && possible_tile_right != index_to_set) {
+ gl_render_set_rotation(M_PI);
+ renderer->render_image_tint(img_arrow_left_rounded, tx + timeslot_w + icon_pad-1, icon_y, icon_s+2, icon_s,COLOR_SCHEDULE_BORDER_THIN);
+ renderer->render_image_tint(img_arrow_left_rounded, tx + timeslot_w + icon_pad, icon_y, icon_s, icon_s,tile_color);
+ gl_render_set_rotation(0.0f);
+ }
+ }
+
+ // Draw tile.
+ renderer->render_rectangle(tx, ty, timeslot_w, timeslot_h, tile_color);
+
+ // Status icon if tile being scheduled.
+ s32 icon_size = timeslot_w*0.6f;
+ if (scheduled_time.assignee == 0) {
+ renderer->render_image(img_questionmark, tx+(timeslot_w/2)-(icon_size/2),ty+(timeslot_h/5),icon_size,icon_size);
+ }
+ else {
+ renderer->render_image(img_checkmark, tx+(timeslot_w/2)-(icon_size/2),ty+(timeslot_h/5),icon_size,icon_size);
+ }
+ }
+ }
+
+ // existing jobs
+ {
+ for (s32 i = 0; i < _active_location->schedule.jobs.length; i++) {
+ scheduled_job* job = array_at(&_active_location->schedule.jobs, i);
+
+ // if rescheduling, dont show the timeslots for the job being rescheduled.
+ if (_active_schedule_state == RESCHEDULING_JOB && _active_selected_scheduled_job == job) {
+ continue;
+ }
+
+ for (s32 t = 0; t < job->offer.shipday_count; t++) {
+ scheduled_job_time scheduled_time = job->timeslots[t];
+ s32 tx = TILE_X(scheduled_time.timeslot);
+ s32 ty = TILE_Y(scheduled_time.day);
+ bool is_selected_job = (_active_selected_scheduled_job == job);
+ bool is_selected = (is_selected_job && _active_schedule_selected_job_index == t);
+ bool is_inspecting_employee = false;
+
+ if (_active_selected_scheduled_job != 0 && scheduled_time.assignee == _active_selected_scheduled_job->timeslots[_active_schedule_selected_job_index].assignee && !is_selected) {
+ is_inspecting_employee = true;
+ }
+
+ color tc = COLOR_SCHEDULE_TILE_FIXED;
+ if (is_inspecting_employee) {
+ tc = COLOR_SCHEDULE_TILE_HIGHLIGHTED;
+ }
+ else if (is_selected) {
+ tc = COLOR_SCHEDULE_TILE_HOVERED;
+ }
+ if (scheduled_time.assignee == 0) tc = is_selected ? COLOR_SCHEDULE_TILE_HOVERED : COLOR_SCHEDULE_TILE_INVALID;
+ if (is_inspecting_employee || is_selected) {
+ // Draw duration of job.
+ draw_duration_of_scheduled_job_entry(scheduled_time, hour_w, tx, ty, timeslot_w, x, y, timeslot_h, tc);
+ }
+
+ renderer->render_rectangle(tx, ty, timeslot_w, timeslot_h, tc);
+ if (is_selected_job && !is_selected) {
+ s32 dotsize = timeslot_w/3;
+ s32 dotoffsetx = (timeslot_w/2)-(dotsize/2);
+ s32 dotoffsety = timeslot_h-(timeslot_h/4)-(dotsize/2);
+ renderer->render_image_tint(img_dot, tx+dotoffsetx,ty+dotoffsety,dotsize,dotsize,COLOR_SCHEDULE_TILE_HOVERED);
+ }
+
+ // Status icon
+ s32 icon_size = timeslot_w*0.6f;
+ if (scheduled_time.assignee == 0) {
+ renderer->render_image(img_questionmark, tx+(timeslot_w/2)-(icon_size/2),ty+(timeslot_h/5),icon_size,icon_size);
+ }
+
+ #if 0
+ color col = COLOR_SCHEDULE_TILE_FIXED;
+ if (is_selected_job) col = COLOR_SCHEDULE_TILE_HIGHLIGHTED;
+ if (is_selected) col = COLOR_SCHEDULE_TILE_HOVERED;
+ renderer->render_rectangle(tx, ty, timeslot_w, timeslot_h, col);
+ #endif
+
+ #if 0
+ // Viewing job info box.
+ if (is_selected) {
+ s32 tooltip_offset_from_tile = 15*scale;
+ s32 tooltip_pad = 15*scale;
+ s32 tooltip_h = fnt_s->px_h + (tooltip_pad*2);
+ s32 tooltip_x = tx + timeslot_w + tooltip_offset_from_tile;
+ s32 tooltip_y = ty + (timeslot_h/2)-(tooltip_h/2);
+ // if (tx > area.x + (area.w/2))
+
+ char* tooltip_text = "Maastricht -> Machester";
+ s32 tooltip_text_w = renderer->calculate_text_width(fnt_s, tooltip_text);
+ s32 tooltip_w = tooltip_text_w + (tooltip_pad*2);
+
+ renderer->set_render_depth(5);
+ button_draw_background(scale, tooltip_x,tooltip_y,tooltip_w,tooltip_h, COLOR_WHITE, COLOR_BUTTON);
+ renderer->render_text(fnt_s, tooltip_x+tooltip_pad, tooltip_y+tooltip_pad, tooltip_text, COLOR_TEXT);
+ renderer->set_render_depth(4);
+ }
+ #endif
+
+ if (_active_schedule_state == VIEWING && mouse_interacts(tx,ty,timeslot_w,timeslot_h)) {
+ platform_set_cursor(window, CURSOR_POINTER);
+
+ if (is_left_clicked()) {
+ scheduled_job* prev_selected_scheduled_job = _active_selected_scheduled_job;
+ _active_schedule_state = VIEWING;
+ _active_selected_scheduled_job = job;
+ _active_schedule_selected_job_index = t;
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+
+ if (_active_selected_scheduled_job != prev_selected_scheduled_job) {
+ tag_animation = animation_create(TAG_ANIMATION_DURATION);
+ tag_animation.started = true;
+ }
+
+ employee_selector_animation = animation_create(EMPLOYEE_SELECTOR_ANIMATION_DURATION);
+ employee_selector_animation.started = true;
+ }
+ }
+ }
+ }
+ }
+
+ // rows
+ for (s32 ty = 0; ty < ROWS; ty++)
+ {
+ s32 row_y = y + (ty*timeslot_h);
+
+ if (ty==0) {
+ // COLOR_SCHEDULE_ROW_ACTIVE
+ renderer->render_rectangle(x, y, timeslot_w*4, h, COLOR_SCHEDULE_BG);
+ renderer->render_rectangle(x, y, w, timeslot_h, COLOR_SCHEDULE_BG);
+ }
+ else {
+ // Days
+ {
+ char buf[20];
+ switch(ty) {
+ case 1: strcpy(buf, "Mon"); break;
+ case 2: strcpy(buf, "Tue"); break;
+ case 3: strcpy(buf, "Wed"); break;
+ case 4: strcpy(buf, "Thu"); break;
+ case 5: strcpy(buf, "Fri"); break;
+ case 6: strcpy(buf, "Sat"); break;
+ case 7: strcpy(buf, "Sun"); break;
+ }
+
+ s32 tw = renderer->calculate_text_width(fnt, buf);
+ s32 textx = x + (hour_w/2)-(tw/2);
+ s32 texty = row_y + (timeslot_h/2)-(fnt->px_h/2);
+ renderer->render_text(fnt, textx, texty, buf, COLOR_TEXT);
+ }
+ }
+ renderer->render_rectangle(x, row_y, w, 1, COLOR_SCHEDULE_BORDER);
+ }
+
+ // cols
+ for (s32 tx = 0; tx < COLS; tx++)
+ {
+ s32 row_x = x + (tx*timeslot_w);
+ bool is_big_line = tx % 4 == 0;
+ if (tx>=4 || is_big_line) {
+ s32 liney = y;
+ s32 lineh = h;
+ if (!is_big_line) {
+ liney = y+timeslot_h;
+ lineh = h-timeslot_h;
+ }
+ renderer->render_rectangle(row_x, liney, 1, lineh, (is_big_line) ? COLOR_SCHEDULE_BORDER : COLOR_SCHEDULE_BORDER_THIN);
+ }
+ if (tx!=0 && is_big_line) {
+
+ char buf[20];
+ sprintf(buf, "%d:00", WORK_HOUR_START+((tx-1)/TIME_SLOTS_PER_HOUR));
+ s32 tw = renderer->calculate_text_width(fnt, buf);
+ s32 textx = row_x + (hour_w/2)-(tw/2);
+ s32 texty = y + (timeslot_h/2)-(fnt->px_h/2);
+ renderer->render_text(fnt, textx, texty, buf, COLOR_TEXT);
+ }
+ }
+
+ // outline
+ renderer->render_rectangle_outline(x,y,w+1,h+1,1,COLOR_SCHEDULE_BORDER);
+
+ x -= schedule_pad;
+ place_detail_draw_schedule_employee_options(window, schedule_pad, scale, x + selector_w + pad_between_items, employee_select_y, options_w, employee_select_h);
+ place_detail_draw_schedule_employee_selector(window, schedule_pad, scale, x, employee_select_y, selector_w, employee_select_h);
+
+ // Deselect selected job.
+ if (mouse_interacts(x+schedule_pad,y,w+1,h+1) && is_left_clicked()) {
+ if (_active_schedule_state == VIEWING) {
+ _active_selected_scheduled_job = 0;
+ }
+ }
+}
+
+static void place_detail_draw_dealers(platform_window* window)
+{
+ float offset = scale * 40.0;
+ s32 item_h = 82 * 0.4 * scale;
+ s32 h = (area.h * 0.6 - (offset*2)) + item_h;
+ s32 w = (area.w * 0.9 - (offset*2));
+ s32 x = offset + area.x + (area.w*0.05);
+ s32 pos_y = area.y + (area.w*0.12);
+ s32 y = pos_y;
+
+ s32 item_count = _active_world->truck_dealers.length;
+
+ s32 spacing = 6;
+ s32 logo_space_w = w / 7.0f;
+ s32 logo_space_h = (h-(spacing*(item_count-1))) / 3.0f;
+
+ for (s32 i = 0; i < item_count; i++)
+ {
+ truck_dealer* d = array_at(&_active_world->truck_dealers, i);
+ if(button_render(scale, true, 0, x, y + (logo_space_h*i)+spacing*i, logo_space_w, logo_space_h)) active_dealer_index = i;
+ render_logo_at(d->logo, 40 * scale, x, y + (logo_space_h*i)+spacing*i, logo_space_w, logo_space_h);
+ }
+
+ if (active_dealer_index < _active_world->truck_dealers.length) {
+ truck_dealer* d = array_at(&_active_world->truck_dealers, active_dealer_index);
+
+ s32 panel_x = x + spacing + logo_space_w;
+ s32 panel_w = (x + w) - panel_x;
+ place_detail_draw_active_dealer(window, d, scale, panel_x, y, panel_w, h);
+ }
+}
+
+static void place_detail_draw_resumes(platform_window* window)
+{
+ s32 screen_center_x = area.x + (area.w/2);
+ s32 screen_center_y = area.y + (area.h/2);
+ s32 panel_w = area.w*0.75;
+ s32 panel_h = area.h*0.75;
+ s32 panel_x = screen_center_x - (panel_w/2);
+ s32 panel_y = screen_center_y - (panel_h/2);
+
+ bool resume_available = _active_location->resumes.length;
+
+ font* fntb = fnt_rd32;
+ font* fnt = fnt_rd16;
+
+ if (!resume_available) {
+ char* message = "No resumes available.";
+ s32 text_w = renderer->calculate_text_width(fnt, message);
+ s32 text_x = screen_center_x - (text_w/2);
+ s32 text_y = screen_center_y - (fnt->px_h/2);
+ renderer->render_text(fnt, text_x+1, text_y+1, message, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, message, COLOR_TEXT);
+ }
+ else {
+ s32 panel_w = area.w*0.2;
+ s32 panel_h = area.h*0.3;
+ panel_x = screen_center_x - (panel_w/2);
+ panel_y = screen_center_y - (panel_h/2);
+ resume* resume = array_at(&_active_location->resumes, 0);
+
+ float opacity = 1.0f - resume->animation.percentage;
+ if (opacity < 0.0f) opacity = 0.0f;
+
+ color color_bg = COLOR_WHITE;
+ color_bg.a = opacity*255;
+
+ renderer->render_image_tint(img_resume, panel_x, panel_y, panel_w, panel_h, color_bg);
+
+ char buffer[100];
+ sprintf(buffer, "Resume");
+ s32 text_x = panel_x + (panel_w/2) - (renderer->calculate_text_width(fntb, buffer)/2);
+ s32 text_y = panel_y + (20*scale);
+
+ color t_shadow = COLOR_TEXT_SHADOW;
+ t_shadow.a = opacity*255;
+
+ renderer->render_text(fntb, text_x, text_y, buffer, t_shadow);
+
+ text_x = panel_x + (20*scale);
+ text_y += fntb->px_h+(15*scale);
+
+ sprintf(buffer, "Name: %s", resume->employee->name);
+ renderer->render_text(fnt, text_x, text_y, buffer, t_shadow);
+
+ text_y += fnt->px_h + 8*scale;
+ sprintf(buffer, "Age: %d", resume->employee->age);
+ renderer->render_text(fnt, text_x, text_y, buffer, t_shadow);
+
+ text_y += fnt->px_h + 8*scale;
+ sprintf(buffer, "Experience: %d years", resume->employee->experience);
+ renderer->render_text(fnt, text_x, text_y, buffer, t_shadow);
+
+ text_y += fnt->px_h + 8*scale;
+ sprintf(buffer, "Salary: $%.2f/month", resume->employee->salary);
+ renderer->render_text(fnt, text_x, text_y, buffer, t_shadow);
+
+ struct tm* curr_time = gmtime(&resume->expire_date);
+ text_y += fnt->px_h + 8*scale;
+ strftime(buffer, 50, "Offer open untill %d/%m/%Y", curr_time);
+ renderer->render_text(fnt, text_x, text_y, buffer, t_shadow);
+ text_y += fnt->px_h + 8*scale;
+
+ s32 signature_h = ((panel_y+panel_h)-text_y)*0.6;
+ text_y += (10 * scale);
+ renderer->render_image(img_signature, text_x, text_y, signature_h*2, signature_h);
+
+ if (!resume->animation.started) {
+ s32 button_w = 124 * scale;
+ s32 button_h = 37 * scale;
+ s32 pad = 20 * scale;
+ s32 btn_y = panel_y + panel_h + pad;
+ s32 btn_x = panel_x;
+ if (button_render(scale, true, "Hire", btn_x, btn_y, button_w, button_h)) {
+ audio_play_sound(snd_click2, AUDIO_CHANNEL_SFX_1);
+ resume->animation.started = true;
+ resume->hired = true;
+ resume->employee->id = _active_world->next_id++;
+ resume->employee->hire_date = _active_world->current_time;
+ add_employee_to_world_location(_active_location, resume->employee);
+ }
+ btn_x = panel_x + panel_w - button_w;
+ if (button_render(scale, true, "Decline", btn_x, btn_y, button_w, button_h)) {
+ audio_play_sound(snd_click3, AUDIO_CHANNEL_SFX_1);
+ resume->animation.started = true;
+ resume->hired = false;
+ }
+ }
+ else {
+ s32 pad = scale * 50;
+ s32 stamp_x = panel_x + pad;
+ s32 stamp_y = panel_y + pad;
+ s32 stamp_w = panel_w - (pad*2);
+ s32 stamp_h = panel_h - (pad*2);
+ if (resume->hired) {
+ renderer->render_image_tint(img_hired, stamp_x, stamp_y, stamp_w, stamp_h, color_bg);
+ }
+ else {
+ renderer->render_image_tint(img_denied, stamp_x, stamp_y, stamp_w, stamp_h, color_bg);
+ }
+
+ animation_update(&resume->animation);
+ if (resume->animation.percentage == 1.0f) {
+ array_remove_at(&_active_location->resumes, 0);
+ }
+ }
+ }
+}
+
+static void place_detail_draw_info(platform_window* window, tab tab)
+{
+ float pad = tab.scale * 10;
+ float x = tab.x+pad;
+ float y = tab.y+pad;
+ float w = tab.w-(pad*2);
+ float h = tab.h-(pad*2);
+
+ renderer->render_set_scissor(window, x, y, w, h);
+ if (selected_tab_index == PLACE_DETAIL_EMPLOYEES) {
+ place_detail_draw_employees(window, tab, x, y, w, h);
+ }
+ else if (selected_tab_index == PLACE_DETAIL_JOBOFFERS) {
+ place_detail_draw_job_offers(window, tab, x, y, w, h);
+ }
+ else if (selected_tab_index == PLACE_DETAIL_GARAGE) {
+ place_detail_draw_trucks(window, tab, x, y, w, h);
+ }
+
+ renderer->render_reset_scissor(window);
+}
+
+static tab place_detail_draw_tab_bg(platform_window* window)
+{
+ float offset = scale * 40.0;
+ s32 cornor_size = img_button_topleft->width*(scale/2);
+ s32 item_h = 82 * 0.4 * scale;
+ s32 h = (area.h * 0.6 - (offset*2));
+ s32 w = (area.w * 0.9 - (offset*2));
+ s32 top_width = w - (cornor_size*2);
+ s32 size_height = h - (cornor_size*2);
+ s32 x = offset + area.x + (area.w*0.05);
+ s32 pos_y = area.y + (area.w*0.12);
+ s32 y = pos_y + item_h;
+
+ color fill = COLOR_BUTTON_ACTIVE_TINT;
+
+ // button_render(scale, BUTTON_STATIC, 0, panel_x + pad_x, vertical_pad + panel_y + pad_y*2 + button_h*1, button_w, button_h);
+
+ // left
+ renderer->render_image_tint(img_button_left, x, y-1, cornor_size, size_height+2, fill);
+
+ // right
+ renderer->render_image_tint(img_button_right, x + cornor_size + top_width, y-1, cornor_size, size_height+2, fill);
+
+ // bottom
+ renderer->render_image_tint(img_button_bottomleft, x, y + size_height, cornor_size, cornor_size, fill);
+ renderer->render_image_tint(img_button_bottom, x + cornor_size, y + size_height, top_width, cornor_size, fill);
+ renderer->render_image_tint(img_button_bottomright, x + cornor_size + top_width, y + size_height, cornor_size, cornor_size, fill);
+
+ // fill
+ s32 pad = cornor_size-1;
+ fill = COLOR_BUTTON_ACTIVE;
+ renderer->render_rectangle(x+pad, y-1, w-(pad*2), h-(pad*2), fill);
+
+ return (tab){x,y,w,h, scale};
+}
+
+static void place_detail_push_tab(place_detail_info_state index, platform_window* window, char* text)
+{
+ float offset = scale * 40.0;
+ s32 pos_y = area.y + (area.w*0.12);
+ s32 item_w = 426 * 0.4 * scale;
+ s32 item_h = 82 * 0.4 * scale;
+ s32 pos_x = offset + area.x + (area.w*0.05) + (item_w*index);
+ bool hovered = mouse_interacts(pos_x,pos_y,item_w,item_h);
+
+ color tint = COLOR_WHITE;
+ if (selected_tab_index == index) {
+ tint = COLOR_BUTTON_ACTIVE_TINT;
+ }
+ if (hovered) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ if (is_left_clicked()) {
+ if (selected_tab_index != index) audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ selected_tab_index = index;
+ }
+ }
+
+ renderer->render_image_tint(img_tabitem, pos_x, pos_y, item_w, item_h, tint);
+
+ {
+ font* fnt = fnt_rd24;
+ s32 text_x = pos_x + (item_w/2) - (renderer->calculate_text_width(fnt, text)/2);
+ s32 text_y = pos_y + (item_h/2) - (fnt->px_h/2);
+
+ renderer->render_text(fnt, text_x+1, text_y+1, text, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, text, COLOR_TEXT);
+ }
+}
+
+static tab place_detail_draw_tabs(platform_window* window)
+{
+ place_detail_push_tab(PLACE_DETAIL_EMPLOYEES, window, "Employees");
+ place_detail_push_tab(PLACE_DETAIL_JOBOFFERS, window, "Job Offers");
+ place_detail_push_tab(PLACE_DETAIL_SCHEDULE, window, "Schedule");
+ place_detail_push_tab(PLACE_DETAIL_GARAGE, window, "Garage");
+ return place_detail_draw_tab_bg(window);
+}
+
+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);
+ }
+ else if (current_detail_state == PLACE_DETAIL_SHOW_RESUMES) {
+ strcpy(buf, "Hire new employees");
+ }
+ else if (current_detail_state == PLACE_DETAIL_SHOW_DEALERS) {
+ strcpy(buf, "Dealers");
+ }
+ else if (current_detail_state == PLACE_DETAIL_SHOW_EMPLOYEE) {
+ sprintf(buf, "%s, #%d", _active_employee->name, _active_employee->id);
+ }
+ else if (current_detail_state == PLACE_DETAIL_SHOW_SCHEDULE) {
+ if (_active_schedule_state == VIEWING)
+ sprintf(buf, "Schedule for %s", _active_location->name);
+ else {
+ sprintf(buf, "%s wants you to ship %s to %s",
+ _active_scheduling_job.offer.company->name,
+ _active_scheduling_job.offer.product->name,
+ (*(world_location**)array_at(&_active_scheduling_job.offer.connections,
+ _active_scheduling_job.offer.connections.length-1))->name);
+ }
+ }
+
+ 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);
+
+ // Title
+ {
+ renderer->render_text(fnt, text_x+2, text_y+2, buf, COLOR_TEXT_SHADOW);
+ renderer->render_text(fnt, text_x, text_y, buf, COLOR_TEXT);
+ }
+
+ color tags_text_color = AN_LI_TINT(COLOR_TEXT, tag_animation);
+ color tag_icon_color = AN_LI_TINT(COLOR_WHITE, tag_animation);
+
+ // Tags
+ #define PUSH_TAG(_text, _icon){\
+ char* text = _text;\
+ s32 textw = renderer->calculate_text_width(fnt, text);\
+ text_x -= textw;\
+ renderer->render_text(fnt, text_x, text_y, text, tags_text_color);\
+ text_x -= icon_s + pad_between_icon_and_text;\
+ renderer->render_image_tint(_icon, text_x, text_y,icon_s,icon_s, tag_icon_color);\
+ text_x -= pad_between_tags;}
+
+ text_y += (fnt->px_h/2);
+ fnt = fnt_rd20;
+ text_y -= (fnt->px_h/2);
+ s32 icon_s = fnt->px_h;
+ s32 pad_between_icon_and_text = 5*scale;
+ s32 pad_between_tags = 20*scale;
+
+ #define ANIMATION_OFFSET (30*scale)
+ text_x = area.x + (area.w*0.05) + (area.w*0.9) - text_pad + (ANIMATION_OFFSET-(ANIMATION_OFFSET*tag_animation.percentage));
+ #undef ANIMATION_OFFSET
+
+ job_offer* job_to_inspect = 0;
+ if (current_detail_state == PLACE_DETAIL_SHOW_SCHEDULE && _active_schedule_state != VIEWING)
+ job_to_inspect = &_active_scheduling_job.offer;
+ if (current_detail_state == PLACE_DETAIL_SHOW_SCHEDULE && _active_schedule_state == VIEWING && _active_selected_scheduled_job != 0)
+ job_to_inspect = &_active_selected_scheduled_job->offer;
+
+ if (current_detail_state == PLACE_DETAIL_SHOW_SCHEDULE && job_to_inspect) {
+ // price
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "$%d/trip", job_to_inspect->reward);
+ PUSH_TAG(pricebuf, img_coins);
+ }
+
+ // distance
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "%.0fkm", job_to_inspect->total_distance);
+ PUSH_TAG(pricebuf, img_road);
+ }
+
+ // duration
+ {
+ char pricebuf[25];
+ sprintf(pricebuf, "%.0fh-%.0fh", job_to_inspect->duration_sec_min/3600.0f, job_to_inspect->duration_sec_max/3600.0f);
+ PUSH_TAG(pricebuf, img_timer);
+ }
+
+ if (_active_schedule_state == VIEWING) {
+ char namebuf[MAX_WORLD_LOCATION_NAME_LENGTH*3];
+ job_endpoints endpoints = job_offer_get_endpoints(job_to_inspect);
+ sprintf(namebuf, "%s to %s", endpoints.source->name, endpoints.dest->name);
+ PUSH_TAG(namebuf, img_globe);
+ }
+ }
+ else if (current_detail_state == PLACE_DETAIL_SHOW_EMPLOYEE) {
+ // Original location
+ {
+ char pricebuf[100];
+ sprintf(pricebuf, "From: %s", get_world_location_by_id(_active_world, _active_employee->original_location_id)->name);
+ PUSH_TAG(pricebuf, img_city);
+ }
+
+ // Current location or active trip destination
+ {
+ char pricebuf[100];
+ if (_active_employee->current_location_id != INVALID_ID) {
+ sprintf(pricebuf, "Currently at: %s", get_world_location_by_id(_active_world, _active_employee->current_location_id)->name);
+ }
+ else if (_active_employee->active_job_id != INVALID_ID) {
+ active_job* j = get_active_job_by_id(_active_world, _active_employee->active_job_id);
+ job_endpoints endpoints = job_offer_get_endpoints(&j->offer);
+ sprintf(pricebuf, "Driving to: %s", endpoints.dest->name);
+ }
+ PUSH_TAG(pricebuf, img_location_pin);
+ }
+ }
+
+ animation_update(&tag_animation);
+}
+
+static void place_detail_draw_panel(platform_window* window)
+{
+ s32 panel_w = area.w*0.9;
+ s32 panel_h = area.h*0.7;
+ s32 panel_x = area.x + area.w*0.05;
+ s32 panel_y = area.y + area.w*0.05;
+ panel_render(scale, panel_x, panel_y, panel_w, panel_h);
+
+ // back button
+ {
+ s32 back_h = img_back->height * scale/2;
+ s32 back_w = img_back->width * scale/2;
+ s32 back_x = panel_x + (panel_w/10.0f);
+ s32 back_y = panel_y + panel_h - (back_h/2) - 1;
+
+ if (push_back_button(scale, back_x, back_y, back_w, back_h)) {
+ if (current_detail_state == PLACE_DETAIL_SHOW_MAIN) {
+ game_set_active_scene(GAME_STATE_WORLD_MAP);
+ }
+ else {
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+ }
+ _goto_default_detail_state();
+ }
+ }
+
+ if (mouse_interacts(panel_x,panel_y,panel_w,panel_h)) {
+ reset_left_click();
+ }
+ else if (is_left_clicked()) {
+ _goto_default_detail_state();
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ game_set_active_scene(GAME_STATE_WORLD_MAP);
+ }
+}
+
+void place_detail_scene_render(platform_window* window)
+{
+ renderer->set_render_depth(5);
+ world_map_draw_info_panel(window, false);
+
+ renderer->set_render_depth(4);
+ if (current_detail_state == PLACE_DETAIL_SHOW_MAIN) {
+ tab t = place_detail_draw_tabs(window);
+ place_detail_draw_info(window, t);
+
+ 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);
+ }
+ if (current_detail_state == PLACE_DETAIL_SHOW_DEALERS) {
+ place_detail_draw_dealers(window);
+ }
+ if (current_detail_state == PLACE_DETAIL_SHOW_EMPLOYEE) {
+ place_detail_draw_selected_employee(window);
+ }
+ if (current_detail_state == PLACE_DETAIL_SHOW_SCHEDULE) {
+ place_detail_draw_schedule(window);
+ }
+
+ renderer->set_render_depth(3);
+ place_detail_draw_title(window);
+
+ renderer->set_render_depth(2);
+ place_detail_draw_panel(window);
+
+ renderer->set_render_depth(1);
+ menu_draw_background(window);
+}
+
+void place_detail_scene_update(platform_window* window)
+{
+ // world_update(window, _active_world, false);
+
+ if (keyboard_is_key_pressed(KEY_ESCAPE)) {
+ if (current_detail_state == PLACE_DETAIL_SHOW_MAIN) {
+ game_set_active_scene(GAME_STATE_WORLD_MAP);
+ }
+ else {
+ current_detail_state = PLACE_DETAIL_SHOW_MAIN;
+ }
+ _goto_default_detail_state();
+ }
+}
+
+void place_detail_scene_destroy()
+{
+
+}
\ No newline at end of file |
