1 /*
2 This file is part of cave9.
3
4 cave9 is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 cave9 is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with cave9. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #ifdef _WIN32
19 # undef __STRICT_ANSI__ // where did it come from? we're running C99 // for string.h: strdup
20 #endif
21 #include <string.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/stat.h>
26 #include <assert.h>
27 #include "score.h"
28 #include "util.h"
29
30 #ifdef _WIN32
31 #include <io.h> // mkdir
32 #endif
33
34 #ifdef GLOBAL_SCORE
35
score_net_finish(Score * score)36 static void score_net_finish (Score* score)
37 {
38 if(score->udp_pkt != NULL) {
39 SDLNet_FreePacket(score->udp_pkt);
40 score->udp_pkt = NULL;
41 }
42
43 if(score->udp_sock != NULL) {
44 SDLNet_UDP_Close(score->udp_sock);
45 score->udp_sock = NULL;
46 }
47 }
48
score_net_init(Score * score,const char * server,int port)49 static void score_net_init (Score* score, const char* server, int port)
50 {
51 if (server == NULL || server[0] == '\0')
52 return;
53
54 if (SDLNet_Init() == -1) {
55 fprintf (stderr, "SDLNet_Init(): %s\n", SDLNet_GetError());
56 exit(1);
57 }
58 atexit (SDLNet_Quit);
59
60 IPaddress addr;
61 score->udp_sock = NULL;
62 score->udp_pkt = NULL;
63 if (SDLNet_ResolveHost (&addr, server, port) == -1) {
64 fprintf(stderr, "SDLNet_ResolveHost('%s',%d): %s\n",
65 server, port, SDLNet_GetError());
66 } else {
67 score->udp_sock = SDLNet_UDP_Open(0);
68 if(score->udp_sock == NULL) {
69 fprintf(stderr, "SDLNet_UDP_Open(): %s\n", SDLNet_GetError());
70 score_net_finish (score);
71 } else {
72 if(SDLNet_UDP_Bind(score->udp_sock, 0, &addr) == -1) {
73 fprintf(stderr, "SDLNet_UDP_Bind(): %s\n", SDLNet_GetError());
74 score_net_finish (score);
75 } else {
76 score->udp_pkt = SDLNet_AllocPacket (GLOBAL_SCORE_LEN);
77 if(score->udp_pkt == NULL) {
78 fprintf(stderr, "SDLNet_AllocPacket(%d): %s\n",
79 GLOBAL_SCORE_LEN, SDLNet_GetError());
80 score_net_finish (score);
81 } else {
82 printf("Score Global init UDP port %d\n", port);
83 }
84 }
85 }
86 }
87 }
88
score_net_update(Score * score)89 static void score_net_update (Score* score)
90 {
91 if (score->udp_sock == NULL) {
92 return;
93 }
94
95 printf("Score Global send %d\n", score->global);
96 snprintf ((char*)score->udp_pkt->data,GLOBAL_SCORE_LEN, "%d\n", score->global);
97 score->udp_pkt->len = GLOBAL_SCORE_LEN;
98 if (SDLNet_UDP_Send (score->udp_sock, 0, score->udp_pkt) == 1)
99 {
100 SDL_Delay (GLOBAL_SCORE_WAIT); // XXX only wait GLOBAL_SCORE_WAIT for hiscores
101 int n = SDLNet_UDP_Recv (score->udp_sock, score->udp_pkt);
102 if (n == 1) {
103 score->udp_pkt->data[GLOBAL_SCORE_LEN-1] = '\0'; // XXX safeguard
104 sscanf ((char*)score->udp_pkt->data, "%d", &score->global);
105 printf("Score Global recv %d\n", score->global);
106 }
107 else if (n < 0) {
108 fprintf (stderr, "SDLNet_UDP_Recv(%s,%d): %s\n",
109 GLOBAL_SCORE_HOST, GLOBAL_SCORE_PORT, SDLNet_GetError());
110 }
111 }
112 else {
113 fprintf (stderr, "SDLNet_UDP_Send(): %s\n", SDLNet_GetError());
114 }
115 }
116
117 #endif
118
score_init(Score * score,Args * args,int caveseed,int monstal)119 void score_init (Score* score, Args* args, int caveseed, int monstal)
120 {
121 if (args == NULL)
122 return;
123
124 memset (score, 0, sizeof(Score));
125
126 char cave9_home[FILENAME_MAX];
127 char* home = getenv("HOME");
128 if (home != NULL) {
129 sprintf (cave9_home, "%s/.cave9", home);
130 mkdir (
131 cave9_home
132 #ifndef _WIN32 // XXX no mode on win32
133 , 0755
134 #endif
135 );
136 }
137 else {
138 fprintf (stderr,
139 "HOME environment variable not set, using '%s' to save\n",
140 bin_path);
141
142 strncpy(cave9_home, bin_path, FILENAME_MAX-1);
143 cave9_home[FILENAME_MAX-1] = '\0';
144 }
145 size_t len = strlen(cave9_home) + strlen("/") + strlen(SCORE_FILE) + 1;
146 score->filename = malloc (len);
147 snprintf (score->filename, len, "%s/%s", cave9_home, SCORE_FILE);
148 assert (score->filename != NULL);
149
150 const char* paths[] = { "", ".", "~/.cave9", NULL };
151 const char* filename = find_file (SCORE_FILE, paths, false);
152
153 score->local = 0;
154 score->caveseed = caveseed;
155 score->monstal = monstal;
156
157 if(filename != NULL) {
158 FILE* fp = fopen (filename, "r");
159 if (fp != NULL) {
160 int fseed = -1;
161 int fmonstal = 0;
162 int fscore = 0;
163 while(!(fseed == score->caveseed && fmonstal == score->monstal) && !feof(fp))
164 {
165 fscanf (fp, "%11d:%2d:%11d ", &fseed, &fmonstal, &fscore);
166 }
167 if(fseed == caveseed && fmonstal == monstal)
168 score->local = fscore;
169 fclose (fp);
170 }
171 }
172
173 #ifdef GLOBAL_SCORE
174 score_net_init (score, args->server, args->port);
175 #endif
176 }
177
score_finish(Score * score)178 void score_finish (Score* score)
179 {
180 #ifdef GLOBAL_SCORE
181 score_net_finish (score);
182 #endif
183 free (score->filename);
184 score->filename = NULL;
185 }
186
score_update(Score * score,int new_score,bool is_global)187 void score_update (Score* score, int new_score, bool is_global)
188 {
189 if (new_score > score->session)
190 score->session = new_score;
191
192 if (is_global) {
193
194 if (new_score > score->local) {
195 score->local = new_score;
196 FILE* fp = fopen (score->filename, "r+");
197 bool readwrite = true;
198 if (fp == NULL)
199 {
200 // file didn't exist yet, we need to create an empty one
201 fp = fopen (score->filename, "w");
202 readwrite = false;
203 }
204 if (fp == NULL) {
205 perror ("failed to open score file");
206 } else {
207 int fseed = -1;
208 int fmonstal = 0;
209 int fscore = 0;
210 bool found = false;
211 if (readwrite)
212 {
213 while (!feof(fp) && !found)
214 {
215 fscanf (fp, "%11d:%2d:%11d", &fseed, &fmonstal, &fscore);
216 if (fseed == score->caveseed && fmonstal == score->monstal)
217 {
218 if (fscore <= score->local)
219 {
220 fseek(fp, -11, SEEK_CUR);
221 fprintf(fp, "%011d", score->local);
222 }
223 found = true;
224 }
225 }
226 }
227 if (!found || !readwrite)
228 {
229 fprintf(fp, "%011d:%02d:%011d\n", score->caveseed, score->monstal, score->local);
230 }
231 fclose (fp);
232 }
233 }
234
235 int new_global = MAX(new_score, score->local);
236 if (new_global > score->global) {
237 score->global = new_global;
238 #ifdef GLOBAL_SCORE
239 score_net_update (score);
240 #endif
241 }
242 }
243 }
244
245 // vim600:fdm=syntax:fdn=1:
246