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