home · contact · privacy
Improved and defined more precisely textfile_sizes().
[plomrogue] / src / misc.c
1 /* misc.c */
2
3 #include "misc.h"
4 #include <stdio.h> /* for rename() */
5 #include <unistd.h> /* for unlink(), acess() */
6 #include <stdlib.h> /* for calloc(), free() */
7 #include <string.h> /* for strlen(), strcmp(), memcpy() */
8 #include <stdint.h> /* for uint8_t, uint16_t */
9 #include "readwrite.h" /* for [read/write]_uint[8/16/32][_bigendian]() */
10 #include "map_objects.h" /* for struct Monster, write_map_objects(), */
11 #include "map_object_actions.h" /* for is_passable(), move_monster() */
12 #include "map.h" /* for Map struct */
13 #include "main.h" /* for World struct */
14 #include "yx_uint16.h" /* for yx_uint16 struct */
15 #include "rrand.h" /* for rrand(), rrand_seed() */
16 #include "rexit.h" /* for exit_err() */
17
18
19
20 extern uint8_t textfile_sizes(FILE * file, uint16_t * linemax_p,
21                               uint16_t * n_lines_p)
22 {
23     int c = 0;
24     uint16_t c_count = 0;
25     uint16_t n_lines = 0;
26     uint16_t linemax = 0;
27     while (1)
28     {
29         c = getc(file);
30         if (EOF == c)
31         {
32             break;
33         }
34         c_count++;
35         if ('\n' == c)
36         {
37             if (c_count > linemax)
38             {
39                 linemax = c_count;
40             }
41             c_count = 0;
42             if (n_lines_p)
43             {
44                 n_lines++;
45             }
46         }
47     }
48     if (0 == linemax && 0 < c_count) /* Handle files that consist of only one */
49     {                                /* line / lack newline chars.            */
50         linemax = c_count;
51     }
52
53     if (-1 == fseek(file, 0, SEEK_SET))
54     {
55         return 1;
56     }
57     * linemax_p = linemax;
58     if (n_lines_p)
59     {
60         * n_lines_p = n_lines;
61     }
62     return 0;
63 }
64
65
66
67 extern void update_log(struct World * world, char * text)
68 {
69     static char * last_msg;                 /* TODO: valgrind is dissatisfied */
70     if (0 == last_msg)                      /* with this calloc'd pointer     */
71     {                                       /* never being freed.             */
72         last_msg = calloc(1, sizeof(char)); /* Rectify this ?                 */
73     }
74     char * new_text;
75     uint16_t len_old = strlen(world->log);
76     if (0 == strcmp(last_msg, text))
77     {
78         uint16_t len_whole = len_old + 1;
79         new_text = calloc(len_whole + 1, sizeof(char));
80         memcpy(new_text, world->log, len_old);
81         memcpy(new_text + len_old, ".", 1);
82     }
83     else
84     {
85         uint16_t len_new = strlen(text);
86         uint16_t len_whole = len_old + len_new + 1;
87         new_text = calloc(len_whole, sizeof(char));
88         memcpy(new_text, world->log, len_old);
89         memcpy(new_text + len_old, text, len_new);
90         last_msg = calloc(len_new + 1, sizeof(char));
91         memcpy(last_msg, text, len_new);
92     }
93     free(world->log);
94     world->log = new_text;
95 }
96
97
98
99 extern uint16_t center_offset(uint16_t pos, uint16_t mapsize,
100                               uint16_t framesize)
101 {
102     uint16_t offset = 0;
103     if (mapsize > framesize)
104     {
105         if (pos > framesize / 2)
106         {
107             if (pos < mapsize - (framesize / 2))
108             {
109                 offset = pos - (framesize / 2);
110             }
111             else
112             {
113                 offset = mapsize - framesize;
114             }
115         }
116     }
117     return offset;
118 }
119
120
121
122 extern void turn_over(struct World * world, char action)
123 {
124     char * err_open  = "Trouble in turn_over() with fopen() "
125                        "opening file 'record_tmp' for appending.";
126     char * err_write = "Trouble in turn_over() with write_uint8() "
127                        "writing to opened file 'record_tmp'.";
128     char * err_close = "Trouble in turn_over() with fclose() "
129                        "closing opened file 'record'.";
130     char * err_unl   = "Trouble in turn_over() with unlink() "
131                        "unlinking old file 'record'.";
132     char * err_move  = "Trouble in turn_over() with rename() "
133                        "renaming file 'record_tmp' to 'record'.";
134     char * recordfile_tmp = "record_tmp";
135     char * recordfile     = "record";
136     if (1 == world->interactive)
137     {
138         FILE * file_old = fopen(recordfile, "r");
139         FILE * file_new = fopen(recordfile_tmp, "w");
140         exit_err(0 == file_old, world, err_open);
141         char c = fgetc(file_old);
142         while (EOF != c)
143         {
144             exit_err(write_uint8(c, file_new), world, err_write);
145             c = fgetc(file_old);
146         }
147         exit_err(fclose(file_old), world, err_close);
148         exit_err(write_uint8(action, file_new), world, err_write);
149         err_close = "Trouble in turn_over() with fclose() "
150                     "closing opened file 'record_tmp'.";
151         exit_err(fclose(file_new), world, err_close);
152         exit_err(unlink(recordfile), world, err_unl);
153         exit_err(rename(recordfile_tmp, recordfile), world, err_move);
154     }
155     world->turn++;
156     rrand_seed(world->seed * world->turn);
157     struct Monster * monster;
158     for (monster = world->monster;
159          monster != 0;
160          monster = monster->map_obj.next)
161     {
162         move_monster(world, monster);
163     }
164 }
165
166
167
168 extern void save_game(struct World * world)
169 {
170     char * err_open  = "Trouble in save_game() with fopen() "
171                        "opening file 'savefile_tmp' for writing.";
172     char * err_write = "Trouble in save_game() "
173                        "writing to opened file 'savefile_tmp'.";
174     char * err_close = "Trouble in save_game() with fclose() "
175                        "closing opened file 'savefile_tmp'.";
176     char * err_unl   = "Trouble in save_game() with unlink() "
177                        "unlinking old 'savefile' file.";
178     char * err_move  = "Trouble in save_game() with rename() "
179                        "renaming 'file savefile_tmp' to 'savefile'.";
180     char * savefile_tmp = "savefile_tmp";
181     char * savefile     = "savefile";
182     FILE * file = fopen(savefile_tmp, "w");
183     exit_err(0 == file, world, err_open);
184     if (   write_uint32_bigendian(world->seed, file)
185         || write_uint32_bigendian(world->turn, file)
186         || write_uint16_bigendian(world->score, file)
187         || write_uint16_bigendian(world->player->pos.y + 1, file)
188         || write_uint16_bigendian(world->player->pos.x + 1, file)
189         || write_uint8(world->player->hitpoints, file)
190         || write_map_objects(world, world->monster, file)
191         || write_map_objects(world, world->item, file))
192     {
193         exit_err(1, world, err_write);
194     }
195     exit_err(fclose(file), world, err_close);
196     if (!access(savefile, F_OK))
197     {
198         exit_err(unlink(savefile), world, err_unl);
199     }
200     exit_err(rename(savefile_tmp, savefile), world, err_move);
201 }
202
203
204
205 extern struct yx_uint16 find_passable_pos(struct Map * map)
206 {
207     struct yx_uint16 pos;
208     for (pos.y = pos.x = 0; 0 == is_passable(map, pos);)
209     {
210         pos.y = rrand() % map->size.y;
211         pos.x = rrand() % map->size.x;
212     }
213     return pos;
214 }