From 6f7374c2fa58c8692b51018864b802e6b876d305 Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Sat, 23 Nov 2024 21:52:24 +0100 Subject: A new start --- src/scenes/world_map.c | 1094 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1094 insertions(+) create mode 100644 src/scenes/world_map.c (limited to 'src/scenes/world_map.c') diff --git a/src/scenes/world_map.c b/src/scenes/world_map.c new file mode 100644 index 0000000..eb106cb --- /dev/null +++ b/src/scenes/world_map.c @@ -0,0 +1,1094 @@ +typedef enum t_world_map_scene_state +{ + WORLD_SCENE_STATE_IDLE, + WORLD_SCENE_STATE_PURCHASE_LOCATION, + WORLD_SCENE_STATE_LOG, + WORLD_SCENE_STATE_INSIGHTS, + WORLD_SCENE_STATE_INVEST, +} world_map_scene_state; + +typedef union t_world_map_scene_data +{ + world_location* location_to_purchase; +} world_map_scene_data; + +s32 insights_selected_year_index = 0; // years since first year. +world* _active_world = 0; +world_map_scene_state scene_state = WORLD_SCENE_STATE_IDLE; +world_map_scene_data scene_data = {0}; +active_job_ref currently_viewing_active_job = {0,0,0}; + +animation log_button_flash_animation = {0,0,0,1}; + +void place_detail_show_employee_detail(employee* emp); +void place_detail_show_schedule_with_highlighted_job(world_location* loc, scheduled_job* job, scheduled_job_time job_time); + +void world_map_set_active_world(world* world) +{ + _active_world = world; +} + +void world_map_scene_init() +{ + +} + +static bool push_info_panel_button(float scale, image* img, s32 x, s32 y, s32 size, bool enabled, bool flashing) +{ + button_type type = (enabled ? ((flashing && log_button_flash_animation.percentage >= 0.5f) ? BUTTON_HIGHLIGHTED : BUTTON_ENABLED) : BUTTON_DISABLED); + bool result = button_render(scale, type, 0, x, y, size, size); + + float img_size = size / 2; + renderer->render_image(img, x+(img_size/2), y + (img_size/2), img_size, img_size); + return result; +} + +static void world_map_draw_speed_panel(platform_window* window, bool enabled) +{ + s32 screen_center_x = area.x + (area.w/2); + + s32 panel_h = 60 * scale; + s32 panel_w = 180 * scale; + + float btn_size = 23 * scale; + float pad_top = 6 * scale; + s32 panel_x = screen_center_x - (panel_w/2); + s32 panel_y = area.y + area.h - panel_h - (100 * scale); + s32 text_y = panel_y + pad_top; + float side_btn_offset = pad_top; + + // Background panel + panel_render(scale, panel_x, panel_y, panel_w, panel_h); + + // Button decrease simulation speed + if (push_info_panel_button(scale, img_arrow_left, screen_center_x - (panel_w/2) + side_btn_offset, text_y, btn_size, enabled, false)) { + _active_world->simulation_speed/=2; + } + // Button increase simulation speed + if (push_info_panel_button(scale, img_arrow_right, screen_center_x + (panel_w/2) - btn_size - side_btn_offset, text_y, btn_size, enabled, false)) { + _active_world->simulation_speed*=2; + if (_active_world->simulation_speed == 0) _active_world->simulation_speed = 1; + } + + // Validate new simulation speed + if (_active_world->simulation_speed < MIN_SIMULATION_SPEED) _active_world->simulation_speed = MIN_SIMULATION_SPEED; + if (_active_world->simulation_speed > MAX_SIMULATION_SPEED) _active_world->simulation_speed = MAX_SIMULATION_SPEED; + + // Draw the current speed, or pause icon when paused + if (_active_world->simulation_speed != 0) { + font* fnt = fnt_rd20; + + char buf[10]; + sprintf(buf, "%dx", _active_world->simulation_speed); + + s32 tw = renderer->calculate_text_width(fnt, buf); + s32 textx = panel_x + (panel_w/2)-(tw/2); + renderer->render_text(fnt, textx, text_y+(5*scale), buf, COLOR_TEXT); + } + else { + s32 icon_pad = 4*scale; + s32 icon_s = btn_size-(icon_pad*2); + renderer->render_image(img_pause, panel_x+(panel_w/2)-(icon_s/2), text_y+icon_pad, icon_s, icon_s); + } + + if (mouse_interacts(panel_x,panel_y,panel_w,panel_h)) { + reset_left_click(); + } +} + +static void world_map_draw_info_panel(platform_window* window, bool enabled) +{ + world_map_draw_speed_panel(window, enabled); + + s32 screen_center_x = area.x + (area.w/2); + + float vertical_pad = 20 * scale; + + s32 panel_h = 120 * scale; + s32 panel_w = 280 * scale; + s32 panel_x = screen_center_x - (panel_w/2); + s32 panel_y = area.y + area.h - panel_h - (10 * scale); + + // Draw background panel + panel_render(scale, panel_x, panel_y, panel_w, panel_h); + + if (enabled) { + char txt_buf[50]; + char* text = txt_buf; + s32 text_y; + s32 text_x; + font* font_big = fnt_rd32; + s32 game_title_width; + + // Draw current date and time + { + strftime(txt_buf, 50, "%H:%M %d/%m/%Y", &_active_world->current_time); + game_title_width = renderer->calculate_text_width(font_big, text); + text_y = panel_y + vertical_pad; + text_x = screen_center_x - (game_title_width/2); + + renderer->render_text(font_big, text_x+1, text_y+1, text, COLOR_TEXT_SHADOW); + renderer->render_text(font_big, text_x, text_y, text, COLOR_TEXT); + } + + // Draw money + { + sprintf(txt_buf, "$%.0f", _active_world->money); + text = txt_buf; + font* font_medium = fnt_rd24; + game_title_width = renderer->calculate_text_width(font_medium, text); + text_y = text_y + font_big->px_h + (10 * scale); + text_x = screen_center_x - (game_title_width/2); + + renderer->render_text(font_medium, text_x+1, text_y+1, text, COLOR_TEXT_SHADOW); + renderer->render_text(font_medium, text_x, text_y, text, COLOR_TEXT); + } + + float btn_size = 35 * scale; + float btn_spacing = 2 * scale; + float btn_y = panel_y + panel_h - btn_size - vertical_pad/2; + float total_btn_w = (btn_size+btn_spacing)*4-btn_spacing; + + if (log_button_flash_animation.percentage == 1.0f) log_button_flash_animation = animation_create(1000); + log_button_flash_animation.started = true; + animation_update(&log_button_flash_animation); + + // Graph button + if (push_info_panel_button(scale, img_graph, screen_center_x - (total_btn_w/2) + (btn_size+btn_spacing)*0, btn_y, btn_size, enabled, false)) { + scene_state = (scene_state == WORLD_SCENE_STATE_INSIGHTS) ? WORLD_SCENE_STATE_IDLE : WORLD_SCENE_STATE_INSIGHTS; + } + + // Event log button + if (push_info_panel_button(scale, img_list, screen_center_x - (total_btn_w/2) + (btn_size+btn_spacing)*1, btn_y, btn_size, enabled, _active_world->log.has_unread_messages)) { + scene_state = (scene_state == WORLD_SCENE_STATE_LOG) ? WORLD_SCENE_STATE_IDLE : WORLD_SCENE_STATE_LOG; + } + + // Bank button + push_info_panel_button(scale, img_bank, screen_center_x - (total_btn_w/2) + (btn_size+btn_spacing)*2, btn_y, btn_size, enabled, false); + + // Event log button + if (push_info_panel_button(scale, img_list, screen_center_x - (total_btn_w/2) + (btn_size+btn_spacing)*3, btn_y, btn_size, enabled, _active_world->log.has_unread_messages)) { + scene_state = (scene_state == WORLD_SCENE_STATE_INVEST) ? WORLD_SCENE_STATE_IDLE : WORLD_SCENE_STATE_INVEST; + } + } + else { + s32 icon_s = panel_h/2; + renderer->render_image(img_pause, panel_x+(panel_w/2)-(icon_s/2), panel_y+(panel_h/2)-(icon_s/2), icon_s, icon_s); + } + + if (mouse_interacts(panel_x,panel_y,panel_w,panel_h)) { + reset_left_click(); + } +} + +static void _insights_draw_grid(float scale, bool invalid_location, money_data_collection* collection, s32 grid_rows, s32 grid_cols, s32 textpad, s32 x, s32 y, s32 w, s32 h, s32 width_per_item, s32 height_per_item) +{ + font* fnt = fnt_rd16; + font* fnt_title = fnt_rd24; + + for (s32 i = 0; i < MONTHS_IN_YEAR; i++) { + if (!collection) break; + money_data data = collection->months[i]; + if (isnan(data.total_income)) continue; + + char textbuf[50]; + #define PUSH_VAL(_index, _val, _neg)\ + sprintf(textbuf, "$%.0f", fabs(_val));\ + renderer->render_text(fnt, x + ((i+3)*width_per_item) + (textpad/2), y + (_index*height_per_item)+(height_per_item/2)-(fnt->px_h/2), textbuf, (_neg) ? COLOR_TEXT_NEGATIVE : COLOR_TEXT); + + PUSH_VAL(1, data.income_from_trips, false); + PUSH_VAL(2, data.expenses_from_utility, true); + PUSH_VAL(3, data.expenses_from_healthcare, true); + PUSH_VAL(4, data.expenses_from_repairs, true); + PUSH_VAL(5, data.expenses_from_fuel, true); + PUSH_VAL(6, data.expenses_from_employees, true); + PUSH_VAL(7, data.expenses_from_trucks, true); + // ADD NEW ENTRY HERE + PUSH_VAL(9, data.total_income, false); + PUSH_VAL(10, data.total_expenses, true); + PUSH_VAL(11, data.total_profit, data.total_profit < 0.0f); + } + + renderer->render_rectangle(x, y, width_per_item*3, h, COLOR_SCHEDULE_BG); + renderer->render_rectangle(x, y, w, height_per_item, COLOR_SCHEDULE_BG); + + for (s32 tx = 3; tx < grid_cols; tx++) { + s32 posx = x + tx * width_per_item; + renderer->render_rectangle(posx,y,1,h, COLOR_SCHEDULE_BORDER_THIN); + + char buf[50]; + buf[0] = 0; + + switch(tx-2) { + case 1: strcpy(buf, "Jan"); break; + case 2: strcpy(buf, "Feb"); break; + case 3: strcpy(buf, "Mar"); break; + case 4: strcpy(buf, "Apr"); break; + case 5: strcpy(buf, "May"); break; + case 6: strcpy(buf, "Jun"); break; + case 7: strcpy(buf, "Jul"); break; + case 8: strcpy(buf, "Aug"); break; + case 9: strcpy(buf, "Sep"); break; + case 10: strcpy(buf, "Oct"); break; + case 11: strcpy(buf, "Nov"); break; + case 12: strcpy(buf, "Dec"); break; + default: break; + } + + s32 textw = renderer->calculate_text_width(fnt_title, buf); + renderer->render_text(fnt_title, posx + (width_per_item/2)-(textw/2), y+(height_per_item/2)-(fnt_title->px_h/2), buf, COLOR_TEXT); + } + + for (s32 ty = 0; ty < grid_rows; ty++) { + s32 posy = y + ty * height_per_item; + renderer->render_rectangle(x,posy,w,1, COLOR_SCHEDULE_BORDER_THIN); + + char buf[50]; + buf[0] = 0; + + switch(ty) { + case 1: strcpy(buf, "Income"); break; + case 2: strcpy(buf, "Utility"); break; + case 3: strcpy(buf, "Employee Benefits"); break; + case 4: strcpy(buf, "Repairs"); break; + case 5: strcpy(buf, "Fuel"); break; + case 6: strcpy(buf, "Salaries"); break; + case 7: strcpy(buf, "Trucks"); break; + // ADD NEW ENTRY HERE + case 9: strcpy(buf, "Total Income"); break; + case 10: strcpy(buf, "Total Expenses"); break; + case 11: strcpy(buf, "Total Profit"); break; + default: break; + } + + renderer->render_text(fnt_title, x + textpad, posy+(height_per_item/2)-(fnt_title->px_h/2), buf, COLOR_TEXT); + } + + if (!collection) { + char* txtbuf = invalid_location ? "Invalid location" : "No data for time period"; + s32 textw = renderer->calculate_text_width(fnt_title, txtbuf); + s32 textx = x + (width_per_item*9) - (textw/2); + s32 texty = y + (h/2)-(fnt_title->px_h/2); + renderer->render_text(fnt_title, textx, texty, txtbuf, COLOR_TEXT); + } + + renderer->render_rectangle_outline(x,y,w,h, 1, COLOR_SCHEDULE_BORDER); +} + +static void _insights_draw_chart(platform_window*window, bool invalid_location, float scale, money_data_collection* collection, s32 grid_rows, s32 grid_cols, s32 textpad, s32 x, s32 y, s32 w, s32 h, s32 width_per_item, s32 height_per_item) +{ + font* fnt = fnt_rd16; + font* fnt_big = fnt_rd24; + + s32 xaxis_height = fnt_big->px_h; + h -= xaxis_height; + + s32 max_val = 0; + s32 min_val = INT_MAX; + for (s32 i = 0; i < MONTHS_IN_YEAR; i++) { + if (!collection) break; + money_data data = collection->months[i]; + + #define CHECK_MIN_MAX(_val)\ + if (_val > max_val) max_val = _val;\ + if (_val < min_val) min_val = _val; + + CHECK_MIN_MAX(data.income_from_trips); + CHECK_MIN_MAX(data.expenses_from_utility); + CHECK_MIN_MAX(data.expenses_from_healthcare); + CHECK_MIN_MAX(data.expenses_from_repairs); + CHECK_MIN_MAX(data.expenses_from_fuel); + CHECK_MIN_MAX(data.expenses_from_employees); + CHECK_MIN_MAX(data.expenses_from_trucks); + // ADD NEW ENTRY HERE + CHECK_MIN_MAX(data.total_income); + CHECK_MIN_MAX(data.total_expenses); + CHECK_MIN_MAX(data.total_profit); + } + + if (min_val == INT_MAX) min_val = 0; + + s32 steps = 10; + s32 step_size = 0; + + // Round min and max to nearest 10k + { + s32 max = max_val >= abs(min_val) ? max_val : abs(min_val); + s32 round_to = 10000; + if (max > 10000) round_to = 10000; + if (max > 100000) round_to = 100000; + if (max > 1000000) round_to = 1000000; + if (max > 10000000) round_to = 10000000; + if (max > 100000000) round_to = 100000000; + + max_val = max_val + round_to - max_val % round_to; + if (min_val > round_to) min_val = min_val - min_val % round_to; + else min_val = min_val - round_to - (min_val%round_to); + + // make sure negative and positive y-axis is symmetrical + if (max_val > abs(min_val)) { + min_val = -max_val; + } + else if (max_val < abs(min_val)) { + max_val = abs(min_val); + } + + step_size = (max_val-min_val)/steps; + } + + static bool enabled_categories[10] = {1,1,1,1,1,1,1,1,1,1}; + + color colors[] = { + rgb(87, 82, 208), + rgb(3, 118, 247), + rgb(54, 166, 214), + rgb(50, 140, 250), + rgb(90, 196, 248), + rgb(78, 213, 95), + rgb(252, 200, 3), + rgb(249, 146, 5), + rgb(249, 59, 47), + rgb(249, 45, 82), + }; + + char* legenda_items[] = { + "Income", + "Utility", + "Employee Benefits", + "Repairs", + "Fuel", + "Salaries", + "Trucks", + // ADD NEW ENTRY HERE + "Total Income", + "Total Expenses", + "Total Profit", + }; + + // Legenda + { + s32 text_spacing = 10*scale; + s32 outline_spacing = text_spacing/2; + s32 _index = 0; + + #define PUSH_LEGENDA_ITEM(_text){\ + s32 yy = y+((fnt_big->px_h+text_spacing)*_index);\ + s32 totalw = width_per_item*3;\ + bool hovered = (_global_mouse.x >= x-outline_spacing && _global_mouse.x <= x+totalw+outline_spacing\ + && _global_mouse.y >= yy-outline_spacing && _global_mouse.y <= yy + fnt_big->px_h+outline_spacing);\ + if (hovered) {platform_set_cursor(window, CURSOR_POINTER); if (is_left_clicked())\ + { enabled_categories[_index] = !enabled_categories[_index]; audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1); }}\ + renderer->render_rectangle(x,yy,fnt_big->px_h, fnt_big->px_h, enabled_categories[_index] ? colors[_index] : LEGENDA_COLOR_DISABLED);\ + if (hovered) renderer->render_rectangle(x-outline_spacing,yy-outline_spacing,totalw+(text_spacing),fnt_big->px_h+(text_spacing), LEGENDA_HOVER_BACKGROUND_COLOR);\ + renderer->render_text(fnt_big,x+fnt_big->px_h+text_spacing,yy,_text,COLOR_TEXT);_index++;} + + for (s32 i = 0; i < sizeof(legenda_items)/sizeof(char*); i++) { + PUSH_LEGENDA_ITEM(legenda_items[i]); + } + } + + // Graph y axis + { + s32 linex = x + 4*width_per_item; + + float step_h = (h)/(float)steps; + for (s32 i = 0; i < steps+1; i++) { + char buf[20]; + s32 val = max_val - (step_size*i); + sprintf(buf, "%d", val); + s32 textw = renderer->calculate_text_width(fnt, buf); + renderer->render_text(fnt, x+(width_per_item*4)-textw-(10*scale), y+(step_h*i)-(fnt->px_h/2), buf, COLOR_TEXT); + renderer->render_rectangle(linex, y+h*(i/(float)steps), width_per_item*(MONTHS_IN_YEAR-1), 1, LEGENDA_SUB_COLOR_DISABLED); + } + + { + renderer->render_rectangle(linex, y + h - (h*1.0f), width_per_item*(MONTHS_IN_YEAR-1), 1, LEGENDA_COLOR_DISABLED); + renderer->render_rectangle(linex, y + h - (h*0.5f), width_per_item*(MONTHS_IN_YEAR-1), 1, LEGENDA_COLOR_DISABLED); + renderer->render_rectangle(linex, y + h - (h*0.0f), width_per_item*(MONTHS_IN_YEAR-1), 1, LEGENDA_COLOR_DISABLED); + } + } + + // Graph x axis + for (s32 i = 0; i < MONTHS_IN_YEAR; i++) { + char buf[50]; + buf[0] = 0; + + switch(i+1) { + case 1: strcpy(buf, "Jan"); break; + case 2: strcpy(buf, "Feb"); break; + case 3: strcpy(buf, "Mar"); break; + case 4: strcpy(buf, "Apr"); break; + case 5: strcpy(buf, "May"); break; + case 6: strcpy(buf, "Jun"); break; + case 7: strcpy(buf, "Jul"); break; + case 8: strcpy(buf, "Aug"); break; + case 9: strcpy(buf, "Sep"); break; + case 10: strcpy(buf, "Oct"); break; + case 11: strcpy(buf, "Nov"); break; + case 12: strcpy(buf, "Dec"); break; + default: break; + } + s32 textw = renderer->calculate_text_width(fnt,buf); + + renderer->render_text(fnt, x+(width_per_item*(i+4))-(textw/2), y+h+(10*scale), buf, COLOR_TEXT); + } + + // Graph data + { + s32 total_diff = max_val-min_val; + if (total_diff == 0) total_diff = 1; + + s32 dot_size = 4*scale; + s32 dot_offset =dot_size/2; + s32 _index = 0; + //if (min_val < 0) min_val = 0; + + #define DRAW_LINES_FOR_DATA(_var){\ + s32 last_dot_x = 0;\ + s32 last_dot_y = 0;\ + for (s32 i = 0; i < MONTHS_IN_YEAR; i++) {\ + if (!collection) break;\ + if (!enabled_categories[_index]) break;\ + money_data data = collection->months[i];\ + if (isnan(data.total_income)) continue;\ + s32 val_diff = (_var) - min_val;\ + s32 dot_x = x + (i+4)*width_per_item;\ + s32 dot_y = y + h - (h*(val_diff/(float)total_diff));\ + renderer->render_image_tint(img_dot, dot_x-dot_offset, dot_y-dot_offset, dot_size, dot_size, colors[_index]);\ + if (mouse_interacts(dot_x-dot_offset, dot_y-dot_offset, dot_size, dot_size)) {\ + reset_left_click();\ + s32 info_x = dot_x;\ + s32 info_y = dot_y+(dotsize/2);\ + char info_txt[50];\ + sprintf(info_txt, "%s: $%.0f", legenda_items[_index], _var);\ + show_tooltip(info_x, info_y, info_txt);\ + }\ + if (last_dot_x != 0) {\ + renderer->render_line(dot_x, dot_y, last_dot_x, last_dot_y, 1, colors[_index]);\ + }\ + last_dot_x = dot_x;\ + last_dot_y = dot_y;\ + }_index++;\ + } + + DRAW_LINES_FOR_DATA(data.income_from_trips); + DRAW_LINES_FOR_DATA(data.expenses_from_utility); + DRAW_LINES_FOR_DATA(data.expenses_from_healthcare); + DRAW_LINES_FOR_DATA(data.expenses_from_repairs); + DRAW_LINES_FOR_DATA(data.expenses_from_fuel); + DRAW_LINES_FOR_DATA(data.expenses_from_employees); + DRAW_LINES_FOR_DATA(data.expenses_from_trucks); + // ADD NEW ENTRY HERE + DRAW_LINES_FOR_DATA(data.total_income); + DRAW_LINES_FOR_DATA(data.total_expenses); + DRAW_LINES_FOR_DATA(data.total_profit); + } + + if (!collection) { + char* txtbuf = invalid_location ? "Invalid location" : "No data for time period"; + s32 textw = renderer->calculate_text_width(fnt_big, txtbuf); + s32 textx = x + (width_per_item*9) - (textw/2); + s32 texty = y + (h/2)-(fnt_big->px_h/2); + renderer->render_text(fnt_big, textx, texty, txtbuf, COLOR_TEXT); + } +} + +static void world_map_draw_insights(platform_window* window) +{ + s32 w = area.w*0.9; + s32 h = area.h*0.7; + s32 x = area.x + area.w*0.05; + s32 y = area.y + area.w*0.05; + s32 w_orig = w; + s32 h_orig = h; + s32 x_orig = x; + s32 y_orig = y; + panel_render(scale, x, y, w, h); + + #define GRID_ROWS ((sizeof(money_data)/sizeof(float))+2) + #define GRID_COLS (MONTHS_IN_YEAR+3) + + s32 button_row_h = 44*scale; + s32 btn_size = 34*scale; + s32 spacing = 5*scale; + + s32 pad = 40*scale; + s32 halfpad = pad/2; + s32 textpad = 20*scale; + + w -= pad*2; + h -= pad*2; + + h -= button_row_h+spacing; + + s32 width_per_item = (w/GRID_COLS); + s32 height_per_item = (h/GRID_ROWS); + s32 new_w = width_per_item*GRID_COLS; + s32 new_h = height_per_item*GRID_ROWS; + s32 off_x = w - new_w; + s32 off_y = h - new_h; + w = new_w; + h = new_h; + + s32 panel_w = w+(halfpad*2); + + enum insights_panel_format + { + CHART, + GRID, + }; + static enum insights_panel_format current_format = GRID; + static world_location* active_world_location_filter = 0; + + { + s32 btn_row_x = x + off_x/2+halfpad; + s32 btn_row_y = y + off_y/2+halfpad; + + s32 button_pad = (button_row_h - btn_size)/2; + s32 btn_start_x = btn_row_x + panel_w - (4*scale); + s32 btn_left_start_x = btn_row_x+(4*scale)+button_pad; + s32 year_w = (80*scale); + s32 year_text_w = year_w+(button_pad*2); + s32 btn_y = btn_row_y + button_pad; + + // background + button_render(scale, BUTTON_STATIC, 0, btn_row_x, btn_row_y,panel_w, button_row_h); + + // Buttons right + if (push_info_panel_button(scale, img_graph, btn_start_x - ((btn_size + button_pad)*1), btn_y, btn_size, current_format!=CHART, false)) (current_format = CHART); + if (push_info_panel_button(scale, img_grid, btn_start_x - ((btn_size + button_pad)*2), btn_y, btn_size, current_format!=GRID, false)) (current_format = GRID); + + font* fnt = fnt_rd24; + s32 current_year = 1900+_active_world->start_year+insights_selected_year_index; + + // Buttons left + button_render(scale, BUTTON_STATIC, 0, btn_left_start_x+btn_size+button_pad, btn_y,year_w, btn_size); + char buf[10]; + sprintf(buf, "%d", current_year); + s32 textw = renderer->calculate_text_width(fnt,buf); + renderer->render_text(fnt,btn_left_start_x+(btn_size)+(year_text_w/2)-(textw/2), btn_y+(btn_size/2)-(fnt->px_h/2), buf, COLOR_TEXT); + + s32 btn_right_x = btn_left_start_x + (btn_size) + year_text_w; + if (push_info_panel_button(scale, img_arrow_left, btn_left_start_x, btn_y, btn_size, insights_selected_year_index>=1, false)) (insights_selected_year_index--); + if (push_info_panel_button(scale, img_arrow_right, btn_right_x, btn_y, + btn_size, insights_selected_year_index<_active_world->insights.length-1, false)) (insights_selected_year_index++); + + // Location selector + s32 tb_filter_x = btn_right_x + btn_size + button_pad; + s32 tb_width = 520*scale; + active_world_location_filter = location_selector_render(window, scale, true, active_world_location_filter, tb_filter_x, btn_y, tb_width, btn_size); + + // Clear button + s32 clear_btn_x = tb_filter_x + tb_width + button_pad; + if (push_info_panel_button(scale, img_globe, clear_btn_x, btn_y, btn_size, _global_keyboard.input_text_len, false)) { + active_world_location_filter = 0; + keyboard_set_input_text(""); + } + } + + x+=off_x/2+pad; + y+=off_y/2+pad+button_row_h+spacing; + + button_render(scale, BUTTON_STATIC, 0, x-halfpad,y-halfpad,panel_w,h+(halfpad*2)); + + static money_data_collection* prev_collection = 0; + money_data_collection* collection = get_current_insights_data(_active_world); // Get current year page, also a hack to make sure a new page exists at year switch. + if (!prev_collection || collection != prev_collection) { + prev_collection = collection; + insights_selected_year_index = _active_world->insights.length-1; + } + + money_data_collection* collection_to_use = array_at(&_active_world->insights, insights_selected_year_index); // Get page to use + if (active_world_location_filter) { + if (active_world_location_filter->is_owned) { + s32 index_of_filter_page = insights_selected_year_index; + s32 purchase_year_diff = active_world_location_filter->purchase_year - _active_world->start_year; + index_of_filter_page -= purchase_year_diff; + if (index_of_filter_page < 0) collection_to_use = 0; + else if (index_of_filter_page > active_world_location_filter->insights.length-1) collection_to_use = 0; + else collection_to_use = array_at(&active_world_location_filter->insights, index_of_filter_page); + } + else { + collection_to_use = 0; + } + } + + bool is_typing_in_filter_tb = (!active_world_location_filter && _global_keyboard.input_text_len); + if (is_typing_in_filter_tb) collection_to_use = 0; + + if (current_format == GRID) _insights_draw_grid(scale, is_typing_in_filter_tb, collection_to_use, GRID_ROWS, GRID_COLS, textpad, x, y, w, h, width_per_item, height_per_item); + if (current_format == CHART) _insights_draw_chart(window, is_typing_in_filter_tb, scale, collection_to_use, GRID_ROWS, GRID_COLS, textpad, x, y, w, h, width_per_item, height_per_item); + + if (mouse_interacts(x_orig, y_orig, w_orig, h_orig)) { + reset_left_click(); + } else if (is_left_clicked()) { + scene_state = WORLD_SCENE_STATE_IDLE; + } +} + +static void world_map_draw_event_log(platform_window* window) +{ + _active_world->log.has_unread_messages = false; + + font* fnt = fnt_rd16; + + s32 panel_h = area.h*0.9f; + s32 panel_pad = area.h*0.05f; + + s32 panel_w = area.w/3.5f; + + s32 panel_x = area.x + panel_pad; + s32 panel_y = area.y + panel_pad; + panel_render(scale, panel_x, panel_y, panel_w, panel_h); + + float text_pad = panel_w*0.05f; + + s32 text_y = panel_y + text_pad; + s32 text_x = panel_x + text_pad; + s32 text_w = panel_w - (text_pad*2); + + renderer->render_set_scissor(window, text_x, text_y, panel_w, panel_h-(text_pad*2)); + + if (_active_world->log.events.length) { + s32 read_cursor = _active_world->log.write_cursor; + for (s32 i = 0; i < _active_world->log.events.length; i++) { + read_cursor--; + if (read_cursor < 0) read_cursor = _active_world->log.events.length-1; + + 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 (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)); + + if (is_left_clicked()) { + switch (e->type) + { + case EVENT_TYPE_MISSED_SHIPMENT_NO_TRUCK: + place_detail_show_employee_detail((employee*)e->data); + break; + case EVENT_TYPE_MISSED_SHIPMENT_NO_ASSIGNEE: + case EVENT_TYPE_MISSED_SHIPMENT_NOT_AT_LOCATION: { + scheduled_job* job = (scheduled_job*)e->data; + place_detail_show_schedule_with_highlighted_job(job->location, job, e->job_time); + } break; + case EVENT_TYPE_EMPLOYEE_QUIT: + place_detail_show_schedule_with_highlighted_job((world_location*)e->data, 0, e->job_time); + break; + + default: + log_assert(0, "Invalid event type."); + break; + } + } + } + + text_y += highlight_h; + if (text_y > panel_y + panel_h) break; + } + } + else { + char* buf = "No events."; + s32 tw = renderer->calculate_text_width(fnt, buf); + renderer->render_text_cutoff(fnt, text_x + (text_w/2)-(tw/2), text_y, "No events.", COLOR_TEXT, text_w); + } + + renderer->render_reset_scissor(window); + + if (mouse_interacts(panel_x, panel_y, panel_w, panel_h)) { + reset_left_click(); + } else if (is_left_clicked()) { + scene_state = WORLD_SCENE_STATE_IDLE; + } +} + +s32 hovered_investment_panel_item_index = -1; +static s32 world_map_push_invest_panel_item(s32 x, s32 y, s32 w, s32 index, char* text, s32* fval) +{ + s32 pad = 40*scale; + s32 halfpad = pad/2; + s32 panel_w = w-(pad); + float item_pad = 30*scale; + float item_spacing = 5*scale; + float item_halfpad = item_pad/2; + + font* fnt = fnt_rd24; + char value_str[30]; + sprintf(value_str, "$%d", *fval); + float item_h = fnt->px_h+item_pad; + float item_x = x+halfpad; + float item_y = y+halfpad+(index*(item_h+item_spacing)); + float item_w = panel_w; + float content_x = item_x+item_halfpad; + float content_y = item_y+item_halfpad; + float total_val_editor_w = item_w*0.3f; + float button_left_x = item_x + item_w - total_val_editor_w - item_halfpad; + float btn_size = fnt->px_h*2; + float btn_y = item_y + ((item_h-btn_size)/2); + button_render(scale, BUTTON_STATIC, 0, item_x, item_y,item_w,item_h); + renderer->render_text(fnt, content_x, content_y, text, COLOR_TEXT); + // Button decrease simulation speed + if (push_info_panel_button(scale, img_arrow_left, button_left_x, btn_y, btn_size, *fval > 0, false)) { + *fval -= 100.0f; + } + // Button increase simulation speed + if (push_info_panel_button(scale, img_arrow_right, button_left_x+total_val_editor_w-btn_size, btn_y, btn_size, true, false)) { + *fval += 100.0f; + } + s32 item_text_w = renderer->calculate_text_width(fnt, value_str); + s32 item_text_x = button_left_x + (total_val_editor_w/2) - (item_text_w/2); + renderer->render_text(fnt, item_text_x, content_y, value_str, COLOR_TEXT); + + if (mouse_interacts_peak(item_x, item_y, item_w, item_h)) { + hovered_investment_panel_item_index = index; + } + + return item_y + item_h; +} + +static void world_map_draw_invest_panel(platform_window* window) +{ + s32 w = area.w*0.5; + s32 h = area.h*0.7; + s32 x = area.x + area.w*0.25; + s32 y = area.y + area.w*0.05; + panel_render(scale, x, y, w, h); + + s32 pad = 40*scale; + s32 halfpad = pad/2; + s32 panel_w = w-(pad); + + #define TOTAL_INVEST_ITEM_COUNT (5) + + hovered_investment_panel_item_index = -1; + + world_map_push_invest_panel_item(x, y, w, 0, "Workspace safety", (s32*)(&_active_world->investments.safety)); + world_map_push_invest_panel_item(x, y, w, 1, "Marketing", (s32*)(&_active_world->investments.marketing)); + world_map_push_invest_panel_item(x, y, w, 2, "Human resources", (s32*)(&_active_world->investments.human_resources)); + world_map_push_invest_panel_item(x, y, w, 3, "Employee training", (s32*)(&_active_world->investments.training)); + s32 item_bottom = world_map_push_invest_panel_item(x, y, w, 4, "Legal department", (s32*)(&_active_world->investments.legal)); + + float detail_panel_y = item_bottom + halfpad; + float detail_panel_h = h - (detail_panel_y-y)-halfpad; + + button_render(scale, BUTTON_STATIC, 0, x+halfpad, detail_panel_y,panel_w,detail_panel_h); + + s32 info_text_pad = 20*scale; + + char* info_text = 0; + switch (hovered_investment_panel_item_index) + { + case 0: info_text = "Increasing the budget for workspace safety will ensure employees receive the proper workspace safety training."; + break; + case 1: info_text = "Increasing the marketing budget will give your business more publicity and will secure more work proposals."; + break; + case 2: info_text = "Investing in human resources will guarantee more responses to vacancies."; + break; + case 3: info_text = "Providing training for your employees will increase happiness for your employees and make them work more efficiently."; + break; + case 4: info_text = "The legal department is essential for settling legal disputes."; + break; + } + + if (info_text) + renderer->render_text_cutoff(fnt_rd24, x+halfpad+info_text_pad, detail_panel_y+info_text_pad, info_text, COLOR_TEXT, panel_w - (info_text_pad*2)); + + if (mouse_interacts(x,y,w,h)) { + reset_left_click(); + } else if (is_left_clicked()) { + scene_state = WORLD_SCENE_STATE_IDLE; + } +} + +static void world_map_draw_purchase_location_panel(platform_window* window) +{ + s32 screen_center_x = area.x + (area.w/2); + s32 screen_center_y = area.y + (area.h/2); + + float vertical_pad = 20 * scale; + + s32 panel_h = 160 * scale; + s32 panel_w = 280 * scale; + + s32 panel_x = screen_center_x - (panel_w/2); + s32 panel_y = screen_center_y - (panel_h/2); + panel_render(scale, panel_x, panel_y, panel_w, panel_h); + + // info text + { + font* font_title = FONT_REGULAR(SIZE_RD(area.w, 32)); + { + char* title = scene_data.location_to_purchase->name; + s32 text_w = renderer->calculate_text_width(font_title, title); + s32 text_x = screen_center_x - (text_w/2); + s32 text_y = panel_y + (vertical_pad); + renderer->render_text(font_title, text_x+2, text_y+2, title, COLOR_TEXT_SHADOW); + renderer->render_text(font_title, text_x, text_y, title, COLOR_TEXT); + } + { + char buf[100]; + sprintf(buf, "Purchase a garage for $%.0f?", world_location_get_price(scene_data.location_to_purchase)); + char* text = buf; + font* font_info = FONT_REGULAR(SIZE_RD(area.w, 20)); + s32 text_w = renderer->calculate_text_width(font_info, text); + s32 text_x = screen_center_x - (text_w/2); + s32 text_y = panel_y + vertical_pad*1.5+font_title->px_h; + renderer->render_text(font_info, text_x+2, text_y+2, text, COLOR_TEXT_SHADOW); + renderer->render_text(font_info, text_x, text_y, text, COLOR_TEXT); + } + } + + s32 button_w = 178 * scale; + s32 button_h = 37 * scale; + if (button_render(scale, true, "Purchase", screen_center_x - (button_w/2), panel_y + panel_h - button_h - vertical_pad, button_w, button_h)) + { + // Mark as owned. + scene_data.location_to_purchase->is_owned = true; + scene_data.location_to_purchase->purchase_year = _active_world->current_time.tm_year; + + // Make sure insights are ready to display. + money_data_collection* collection = get_current_insights_data_for_location(_active_world, scene_data.location_to_purchase); + collection->months[_active_world->current_time.tm_mon].total_income = 0; + + _active_world->money -= world_location_get_price(scene_data.location_to_purchase); + + scene_state = WORLD_SCENE_STATE_IDLE; + } + + button_w = 30 * scale; + if (button_render(scale, true, "X", panel_x+panel_w-button_w, panel_y+2, button_w, button_w)) + { + scene_state = WORLD_SCENE_STATE_IDLE; + } + + if (mouse_interacts(panel_x,panel_y,panel_w,panel_h)) { + reset_left_click(); + } else if (is_left_clicked()) { + scene_state = WORLD_SCENE_STATE_IDLE; + } +} + +static void world_map_draw_viewing_job(platform_window* window) +{ + active_job* job = get_active_job_by_ref(_active_world, currently_viewing_active_job); + if (!job) { + currently_viewing_active_job.offerid = INVALID_ID; + return; + } + + s32 panel_offset_from_job = area.h*0.1f; + s32 panel_h = area.h*0.32f; + s32 panel_w = area.w*0.15f; + + s32 panel_x = job->px_pos.x; + s32 panel_y = job->px_pos.y; + + if (job->px_pos.y > area.y + (area.h/2)) { + panel_y -= panel_h - panel_offset_from_job; + + renderer->render_line(job->px_pos.x+(dotsize/2), job->px_pos.y+(dotsize/2), panel_x + (panel_w/3), panel_y+panel_h-5, 3, COLOR_INSPECT_ACTIVE_JOB_LINE_CONNECTION); + renderer->render_line(job->px_pos.x+(dotsize/2), job->px_pos.y+(dotsize/2), panel_x + (panel_w/3*2), panel_y+panel_h-5, 3, COLOR_INSPECT_ACTIVE_JOB_LINE_CONNECTION); + } + else { + panel_y += panel_offset_from_job; + + renderer->render_line(job->px_pos.x+(dotsize/2), job->px_pos.y+(dotsize/2), panel_x + (panel_w/3), panel_y+5, 3, COLOR_INSPECT_ACTIVE_JOB_LINE_CONNECTION); + renderer->render_line(job->px_pos.x+(dotsize/2), job->px_pos.y+(dotsize/2), panel_x + (panel_w/3*2), panel_y+5, 3, COLOR_INSPECT_ACTIVE_JOB_LINE_CONNECTION); + } + + panel_render(scale, panel_x, panel_y, panel_w, panel_h); + + s32 panel_pad = 10*scale; + s32 truck_img_x = panel_x + panel_pad; + s32 truck_img_y = panel_y + panel_pad; + s32 truck_img_s = panel_w * 0.6f; + + s32 portrait_s = truck_img_s / 2; + + renderer->render_image(job->assigned_truck.logo, truck_img_x+(panel_pad), truck_img_y, truck_img_s, truck_img_s); + draw_employee_portrait(&job->assignee, truck_img_x+(panel_pad) + truck_img_s - (portrait_s/3), truck_img_y + (truck_img_s / 3), portrait_s, portrait_s); + + { + s32 text_x = truck_img_x; + float text_pad = (5*scale); + s32 text_y = truck_img_y + truck_img_s + panel_pad; + font* fnt = fnt_rd16; + font* fnt_s = fnt_rd12; + renderer->render_text(fnt,text_x,text_y,job->assignee.name,COLOR_TEXT); + text_y += fnt->px_h + text_pad; + + // Name + origin + { + world_location* origin = get_world_location_by_id(_active_world, job->assignee.original_location_id); + char buf[100]; + sprintf(buf, "Works at %s", origin->name); + renderer->render_text(fnt_s,text_x,text_y,buf,COLOR_TEXT); + text_y += fnt_s->px_h + text_pad; + } + + // Job info + { + text_y += (20*scale); + + char daybuf[10]; + switch(job->day) { + case 1: strcpy(daybuf, "Mon"); break; + case 2: strcpy(daybuf, "Tue"); break; + case 3: strcpy(daybuf, "Wed"); break; + case 4: strcpy(daybuf, "Thu"); break; + case 5: strcpy(daybuf, "Fri"); break; + case 6: strcpy(daybuf, "Sat"); break; + case 0: strcpy(daybuf, "Sun"); break; + } + + char buf[100]; + sprintf(buf, "Left on %s %02d:%02d", daybuf, WORK_HOUR_START + (job->timeslot/TIME_SLOTS_PER_HOUR), job->timeslot%TIME_SLOTS_PER_HOUR); + renderer->render_text(fnt_s,text_x,text_y,buf,COLOR_TEXT); + text_y += fnt_s->px_h + text_pad; + } + + // Job status + if (!job->reversed) + { + job_endpoints endpoints = job_offer_get_endpoints(&job->offer); + char buf[100]; + sprintf(buf, "Shipping %s to %s", job->offer.product->name, endpoints.dest->name); + text_y += renderer->render_text_cutoff(fnt_s,text_x,text_y,buf,COLOR_TEXT, panel_w - (panel_pad*2)); + text_y += text_pad; + } + else { + world_location* source = *(world_location**)array_at(&job->offer.connections, 0); // Get source location + char buf[100]; + sprintf(buf, "Returning to %s", source->name); + renderer->render_text_cutoff(fnt_s,text_x,text_y,buf,COLOR_TEXT, panel_w - (panel_pad*2)); + text_y += fnt_s->px_h + text_pad; + } + } + + if (mouse_interacts(panel_x,panel_y,panel_w,panel_h)) { + reset_left_click(); + } else if (is_left_clicked()) { + currently_viewing_active_job.offerid = INVALID_ID; + } +} + +static void world_handle_scroll(platform_window* window) +{ + static float target_zoom = 1.0f; + if (global_ui_context.mouse->scroll_state == SCROLL_UP) + { + if (target_zoom < zoom) target_zoom = zoom; + target_zoom+=0.1f; + } + if (global_ui_context.mouse->scroll_state == SCROLL_DOWN) + { + if (target_zoom > zoom) target_zoom = zoom; + target_zoom-=0.1f; + } + + // Keep camera position + if (target_zoom != zoom) { + vec4 area = camera_get_target_rectangle(window); + int orig_w = area.w * zoom; + int orig_h = area.h * zoom; + int new_w = area.w * target_zoom; + int new_h = area.h * target_zoom; + + float errorw = new_w - orig_w; + float errorh = new_h - orig_h; + camera_x -= errorw / 25.0f; + camera_y -= errorh / 40.0f; + } + + // Smooth scrolling + if (target_zoom != zoom) + { + float error = target_zoom - zoom; + zoom += error / 10; + } + + if (zoom < 1.0f) zoom = 1.0f; + if (zoom > 5.0f) zoom = 5.0f; + + if (camera_x > 0.0f) camera_x = 0.0f; + if (camera_y > 0.0f) camera_y = 0.0f; + + //if (is_left_down_peak()) + { + + } +} + +void world_map_scene_render(platform_window* window) +{ + renderer->set_render_depth(5); + + world_handle_scroll(window); + + world_map_draw_info_panel(window, true); + + renderer->set_render_depth(4); + switch (scene_state) + { + case WORLD_SCENE_STATE_INSIGHTS: + world_map_draw_insights(window); + break; + case WORLD_SCENE_STATE_LOG: + world_map_draw_event_log(window); + break; + case WORLD_SCENE_STATE_IDLE: break; + case WORLD_SCENE_STATE_PURCHASE_LOCATION: + world_map_draw_purchase_location_panel(window); + break; + case WORLD_SCENE_STATE_INVEST: + world_map_draw_invest_panel(window); + break; + } + + renderer->set_render_depth(3); + if (currently_viewing_active_job.offerid != INVALID_ID) world_map_draw_viewing_job(window); + + if (_active_world) { + world_update_result click_result = world_render(window, _active_world); + + if (click_result.clicked_location) { + if (click_result.clicked_location->is_owned) { + place_detail_set_active_location(click_result.clicked_location); + game_set_active_scene(GAME_STATE_PLACE_DETAIL); + } + else { + scene_data.location_to_purchase = click_result.clicked_location; + scene_state = WORLD_SCENE_STATE_PURCHASE_LOCATION; + } + } + else if (click_result.clicked_job) { + currently_viewing_active_job = (active_job_ref){click_result.clicked_job->day, click_result.clicked_job->timeslot, click_result.clicked_job->offer.id}; + } + } + + renderer->set_render_depth(0); + + vec4 area = camera_get_target_rectangle(window); + renderer->render_rectangle(area.x, area.y, area.w, area.h, COLOR_WORLD_MAP_BACKGROUND); + renderer->render_image(img_world_map, area.x + camera_x, area.y + camera_y, area.w*zoom, area.h*zoom); +} + +void world_map_scene_update(platform_window* window) +{ + world_update(window, _active_world); + if (keyboard_is_key_pressed(KEY_ESCAPE)) { + scene_state = WORLD_SCENE_STATE_IDLE; + } +} + +void world_map_scene_destroy() +{ + +} \ No newline at end of file -- cgit v1.2.3-70-g09d2