1 #include "settings.h"
2
3 #include "city/constants.h"
4 #include "core/buffer.h"
5 #include "core/calc.h"
6 #include "core/io.h"
7 #include "core/string.h"
8
9 #define INF_SIZE 560
10 #define MAX_PERSONAL_SAVINGS 100
11 #define MAX_PLAYER_NAME 32
12
13 static struct {
14 // display settings
15 int fullscreen;
16 int window_width;
17 int window_height;
18 // sound settings
19 set_sound sound_effects;
20 set_sound sound_music;
21 set_sound sound_speech;
22 set_sound sound_city;
23 // speed settings
24 int game_speed;
25 int scroll_speed;
26 // misc settings
27 set_difficulty difficulty;
28 set_tooltips tooltips;
29 int monthly_autosave;
30 int warnings;
31 int gods_enabled;
32 int victory_video;
33 // persistent game state
34 int last_advisor;
35 uint8_t player_name[MAX_PLAYER_NAME];
36 // personal savings
37 int personal_savings[MAX_PERSONAL_SAVINGS];
38 // file data
39 uint8_t inf_file[INF_SIZE];
40 } data;
41
load_default_settings(void)42 static void load_default_settings(void)
43 {
44 data.fullscreen = 1;
45 data.window_width = 800;
46 data.window_height = 600;
47
48 data.sound_effects.enabled = 1;
49 data.sound_effects.volume = 100;
50 data.sound_music.enabled = 1;
51 data.sound_music.volume = 80;
52 data.sound_speech.enabled = 1;
53 data.sound_speech.volume = 100;
54 data.sound_city.enabled = 1;
55 data.sound_city.volume = 100;
56
57 data.game_speed = 90;
58 data.scroll_speed = 70;
59
60 data.difficulty = DIFFICULTY_NORMAL;
61 data.tooltips = TOOLTIPS_FULL;
62 data.warnings = 1;
63 data.gods_enabled = 1;
64 data.victory_video = 0;
65 data.last_advisor = ADVISOR_LABOR;
66
67 setting_clear_personal_savings();
68 }
69
load_settings(buffer * buf)70 static void load_settings(buffer *buf)
71 {
72 buffer_skip(buf, 4);
73 data.fullscreen = buffer_read_i32(buf);
74 buffer_skip(buf, 3);
75 data.sound_effects.enabled = buffer_read_u8(buf);
76 data.sound_music.enabled = buffer_read_u8(buf);
77 data.sound_speech.enabled = buffer_read_u8(buf);
78 buffer_skip(buf, 6);
79 data.game_speed = buffer_read_i32(buf);
80 data.scroll_speed = buffer_read_i32(buf);
81 buffer_read_raw(buf, data.player_name, MAX_PLAYER_NAME);
82 buffer_skip(buf, 16);
83 data.last_advisor = buffer_read_i32(buf);
84 buffer_skip(buf, 4); //int save_game_mission_id;
85 data.tooltips = buffer_read_i32(buf);
86 buffer_skip(buf, 4); //int starting_favor;
87 buffer_skip(buf, 4); //int personal_savings_last_mission;
88 buffer_skip(buf, 4); //int current_mission_id;
89 buffer_skip(buf, 4); //int is_custom_scenario;
90 data.sound_city.enabled = buffer_read_u8(buf);
91 data.warnings = buffer_read_u8(buf);
92 data.monthly_autosave = buffer_read_u8(buf);
93 buffer_skip(buf, 1); //unsigned char autoclear_enabled;
94 data.sound_effects.volume = buffer_read_i32(buf);
95 data.sound_music.volume = buffer_read_i32(buf);
96 data.sound_speech.volume = buffer_read_i32(buf);
97 data.sound_city.volume = buffer_read_i32(buf);
98 buffer_skip(buf, 8); // ram
99 data.window_width = buffer_read_i32(buf);
100 data.window_height = buffer_read_i32(buf);
101 buffer_skip(buf, 8); //int max_confirmed_resolution;
102 for (int i = 0; i < MAX_PERSONAL_SAVINGS; i++) {
103 data.personal_savings[i] = buffer_read_i32(buf);
104 }
105 data.victory_video = buffer_read_i32(buf);
106
107 if (buffer_at_end(buf)) {
108 // Settings file is from unpatched C3, use default values
109 data.difficulty = DIFFICULTY_HARD;
110 data.gods_enabled = 1;
111 } else {
112 data.difficulty = buffer_read_i32(buf);
113 data.gods_enabled = buffer_read_i32(buf);
114 }
115 }
116
settings_load(void)117 void settings_load(void)
118 {
119 load_default_settings();
120
121 int size = io_read_file_into_buffer("c3.inf", NOT_LOCALIZED, data.inf_file, INF_SIZE);
122 if (!size) {
123 return;
124 }
125
126 buffer buf;
127 buffer_init(&buf, data.inf_file, size);
128 load_settings(&buf);
129
130 if (data.window_width + data.window_height < 500) {
131 // most likely migration from Caesar 3
132 data.window_width = 800;
133 data.window_height = 600;
134 }
135 }
136
settings_save(void)137 void settings_save(void)
138 {
139 buffer b;
140 buffer *buf = &b;
141 buffer_init(buf, data.inf_file, INF_SIZE);
142
143 buffer_skip(buf, 4);
144 buffer_write_i32(buf, data.fullscreen);
145 buffer_skip(buf, 3);
146 buffer_write_u8(buf, data.sound_effects.enabled);
147 buffer_write_u8(buf, data.sound_music.enabled);
148 buffer_write_u8(buf, data.sound_speech.enabled);
149 buffer_skip(buf, 6);
150 buffer_write_i32(buf, data.game_speed);
151 buffer_write_i32(buf, data.scroll_speed);
152 buffer_write_raw(buf, data.player_name, MAX_PLAYER_NAME);
153 buffer_skip(buf, 16);
154 buffer_write_i32(buf, data.last_advisor);
155 buffer_skip(buf, 4); //int save_game_mission_id;
156 buffer_write_i32(buf, data.tooltips);
157 buffer_skip(buf, 4); //int starting_favor;
158 buffer_skip(buf, 4); //int personal_savings_last_mission;
159 buffer_skip(buf, 4); //int current_mission_id;
160 buffer_skip(buf, 4); //int is_custom_scenario;
161 buffer_write_u8(buf, data.sound_city.enabled);
162 buffer_write_u8(buf, data.warnings);
163 buffer_write_u8(buf, data.monthly_autosave);
164 buffer_skip(buf, 1); //unsigned char autoclear_enabled;
165 buffer_write_i32(buf, data.sound_effects.volume);
166 buffer_write_i32(buf, data.sound_music.volume);
167 buffer_write_i32(buf, data.sound_speech.volume);
168 buffer_write_i32(buf, data.sound_city.volume);
169 buffer_skip(buf, 8); // ram
170 buffer_write_i32(buf, data.window_width);
171 buffer_write_i32(buf, data.window_height);
172 buffer_skip(buf, 8); //int max_confirmed_resolution;
173 for (int i = 0; i < MAX_PERSONAL_SAVINGS; i++) {
174 buffer_write_i32(buf, data.personal_savings[i]);
175 }
176 buffer_write_i32(buf, data.victory_video);
177 buffer_write_i32(buf, data.difficulty);
178 buffer_write_i32(buf, data.gods_enabled);
179
180 io_write_buffer_to_file("c3.inf", data.inf_file, INF_SIZE);
181 }
182
setting_fullscreen(void)183 int setting_fullscreen(void)
184 {
185 return data.fullscreen;
186 }
187
setting_window(int * width,int * height)188 void setting_window(int *width, int *height)
189 {
190 *width = data.window_width;
191 *height = data.window_height;
192 }
193
setting_set_display(int fullscreen,int width,int height)194 void setting_set_display(int fullscreen, int width, int height)
195 {
196 data.fullscreen = fullscreen;
197 if (!fullscreen) {
198 data.window_width = width;
199 data.window_height = height;
200 }
201 }
202
get_sound(set_sound_type type)203 static set_sound *get_sound(set_sound_type type)
204 {
205 switch (type) {
206 case SOUND_MUSIC: return &data.sound_music;
207 case SOUND_EFFECTS: return &data.sound_effects;
208 case SOUND_SPEECH: return &data.sound_speech;
209 case SOUND_CITY: return &data.sound_city;
210 default: return 0;
211 }
212 }
213
setting_sound(set_sound_type type)214 const set_sound *setting_sound(set_sound_type type)
215 {
216 return get_sound(type);
217 }
218
setting_sound_is_enabled(set_sound_type type)219 int setting_sound_is_enabled(set_sound_type type)
220 {
221 return get_sound(type)->enabled;
222 }
223
setting_toggle_sound_enabled(set_sound_type type)224 void setting_toggle_sound_enabled(set_sound_type type)
225 {
226 set_sound *sound = get_sound(type);
227 sound->enabled = sound->enabled ? 0 : 1;
228 }
229
setting_set_sound_volume(set_sound_type type,int volume)230 void setting_set_sound_volume(set_sound_type type, int volume)
231 {
232 set_sound *sound = get_sound(type);
233 sound->volume = calc_bound(volume, 0, 100);
234 }
235
setting_reset_sound(set_sound_type type,int enabled,int volume)236 void setting_reset_sound(set_sound_type type, int enabled, int volume)
237 {
238 set_sound *sound = get_sound(type);
239 sound->enabled = enabled;
240 sound->volume = calc_bound(volume, 0, 100);
241 }
242
setting_game_speed(void)243 int setting_game_speed(void)
244 {
245 return data.game_speed;
246 }
247
setting_increase_game_speed(void)248 void setting_increase_game_speed(void)
249 {
250 if (data.game_speed >= 100) {
251 if (data.game_speed < 500) {
252 data.game_speed += 100;
253 }
254 } else {
255 data.game_speed = calc_bound(data.game_speed + 10, 10, 100);
256 }
257 }
258
setting_decrease_game_speed(void)259 void setting_decrease_game_speed(void)
260 {
261 if (data.game_speed > 100) {
262 data.game_speed -= 100;
263 } else {
264 data.game_speed = calc_bound(data.game_speed - 10, 10, 100);
265 }
266 }
267
setting_scroll_speed(void)268 int setting_scroll_speed(void)
269 {
270 return data.scroll_speed;
271 }
272
setting_increase_scroll_speed(void)273 void setting_increase_scroll_speed(void)
274 {
275 data.scroll_speed = calc_bound(data.scroll_speed + 10, 0, 100);
276 }
277
setting_decrease_scroll_speed(void)278 void setting_decrease_scroll_speed(void)
279 {
280 data.scroll_speed = calc_bound(data.scroll_speed - 10, 0, 100);
281 }
282
setting_reset_speeds(int game_speed,int scroll_speed)283 void setting_reset_speeds(int game_speed, int scroll_speed)
284 {
285 data.game_speed = game_speed;
286 data.scroll_speed = scroll_speed;
287 }
288
setting_tooltips(void)289 set_tooltips setting_tooltips(void)
290 {
291 return data.tooltips;
292 }
293
setting_cycle_tooltips(void)294 void setting_cycle_tooltips(void)
295 {
296 switch (data.tooltips) {
297 case TOOLTIPS_NONE: data.tooltips = TOOLTIPS_SOME; break;
298 case TOOLTIPS_SOME: data.tooltips = TOOLTIPS_FULL; break;
299 default: data.tooltips = TOOLTIPS_NONE; break;
300 }
301 }
302
setting_warnings(void)303 int setting_warnings(void)
304 {
305 return data.warnings;
306 }
307
setting_toggle_warnings(void)308 void setting_toggle_warnings(void)
309 {
310 data.warnings = data.warnings ? 0 : 1;
311 }
312
setting_monthly_autosave(void)313 int setting_monthly_autosave(void)
314 {
315 return data.monthly_autosave;
316 }
317
setting_toggle_monthly_autosave(void)318 void setting_toggle_monthly_autosave(void)
319 {
320 data.monthly_autosave = data.monthly_autosave ? 0 : 1;
321 }
322
setting_gods_enabled(void)323 int setting_gods_enabled(void)
324 {
325 return data.gods_enabled;
326 }
327
setting_toggle_gods_enabled(void)328 void setting_toggle_gods_enabled(void)
329 {
330 data.gods_enabled = data.gods_enabled ? 0 : 1;
331 }
332
setting_difficulty(void)333 set_difficulty setting_difficulty(void)
334 {
335 return data.difficulty;
336 }
337
setting_increase_difficulty(void)338 void setting_increase_difficulty(void)
339 {
340 if (data.difficulty >= DIFFICULTY_VERY_HARD) {
341 data.difficulty = DIFFICULTY_VERY_HARD;
342 } else {
343 data.difficulty++;
344 }
345 }
346
setting_decrease_difficulty(void)347 void setting_decrease_difficulty(void)
348 {
349 if (data.difficulty <= DIFFICULTY_VERY_EASY) {
350 data.difficulty = DIFFICULTY_VERY_EASY;
351 } else {
352 data.difficulty--;
353 }
354 }
355
setting_victory_video(void)356 int setting_victory_video(void)
357 {
358 data.victory_video = data.victory_video ? 0 : 1;
359 return data.victory_video;
360 }
361
setting_last_advisor(void)362 int setting_last_advisor(void)
363 {
364 return data.last_advisor;
365 }
366
setting_set_last_advisor(int advisor)367 void setting_set_last_advisor(int advisor)
368 {
369 data.last_advisor = advisor;
370 }
371
setting_player_name(void)372 const uint8_t *setting_player_name(void)
373 {
374 return data.player_name;
375 }
376
setting_set_player_name(const uint8_t * player_name)377 void setting_set_player_name(const uint8_t *player_name)
378 {
379 string_copy(player_name, data.player_name, MAX_PLAYER_NAME);
380 }
381
setting_personal_savings_for_mission(int mission_id)382 int setting_personal_savings_for_mission(int mission_id)
383 {
384 return data.personal_savings[mission_id];
385 }
386
setting_set_personal_savings_for_mission(int mission_id,int savings)387 void setting_set_personal_savings_for_mission(int mission_id, int savings)
388 {
389 data.personal_savings[mission_id] = savings;
390 }
391
setting_clear_personal_savings(void)392 void setting_clear_personal_savings(void)
393 {
394 for (int i = 0; i < MAX_PERSONAL_SAVINGS; i++) {
395 data.personal_savings[i] = 0;
396 }
397 }
398