/*
This file is part of cave9.
cave9 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cave9 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cave9. If not, see .
*/
#ifdef _WIN32
# undef __STRICT_ANSI__ // where did it come from? we're running C99 // for string.h: strdup
#endif
#include
#include
#include
#include
#include
#include "score.h"
#include "util.h"
#ifdef _WIN32
#include // mkdir
#endif
#ifdef GLOBAL_SCORE
static void score_net_finish (Score* score)
{
if(score->udp_pkt != NULL) {
SDLNet_FreePacket(score->udp_pkt);
score->udp_pkt = NULL;
}
if(score->udp_sock != NULL) {
SDLNet_UDP_Close(score->udp_sock);
score->udp_sock = NULL;
}
}
static void score_net_init (Score* score, const char* server, int port)
{
if (server == NULL || server[0] == '\0')
return;
if (SDLNet_Init() == -1) {
fprintf (stderr, "SDLNet_Init(): %s\n", SDLNet_GetError());
exit(1);
}
atexit (SDLNet_Quit);
IPaddress addr;
score->udp_sock = NULL;
score->udp_pkt = NULL;
if (SDLNet_ResolveHost (&addr, server, port) == -1) {
fprintf(stderr, "SDLNet_ResolveHost('%s',%d): %s\n",
server, port, SDLNet_GetError());
} else {
score->udp_sock = SDLNet_UDP_Open(0);
if(score->udp_sock == NULL) {
fprintf(stderr, "SDLNet_UDP_Open(): %s\n", SDLNet_GetError());
score_net_finish (score);
} else {
if(SDLNet_UDP_Bind(score->udp_sock, 0, &addr) == -1) {
fprintf(stderr, "SDLNet_UDP_Bind(): %s\n", SDLNet_GetError());
score_net_finish (score);
} else {
score->udp_pkt = SDLNet_AllocPacket (GLOBAL_SCORE_LEN);
if(score->udp_pkt == NULL) {
fprintf(stderr, "SDLNet_AllocPacket(%d): %s\n",
GLOBAL_SCORE_LEN, SDLNet_GetError());
score_net_finish (score);
} else {
printf("Score Global init UDP port %d\n", port);
}
}
}
}
}
static void score_net_update (Score* score)
{
if (score->udp_sock == NULL) {
return;
}
printf("Score Global send %d\n", score->global);
snprintf ((char*)score->udp_pkt->data,GLOBAL_SCORE_LEN, "%d\n", score->global);
score->udp_pkt->len = GLOBAL_SCORE_LEN;
if (SDLNet_UDP_Send (score->udp_sock, 0, score->udp_pkt) == 1)
{
SDL_Delay (GLOBAL_SCORE_WAIT); // XXX only wait GLOBAL_SCORE_WAIT for hiscores
int n = SDLNet_UDP_Recv (score->udp_sock, score->udp_pkt);
if (n == 1) {
score->udp_pkt->data[GLOBAL_SCORE_LEN-1] = '\0'; // XXX safeguard
sscanf ((char*)score->udp_pkt->data, "%d", &score->global);
printf("Score Global recv %d\n", score->global);
}
else if (n < 0) {
fprintf (stderr, "SDLNet_UDP_Recv(%s,%d): %s\n",
GLOBAL_SCORE_HOST, GLOBAL_SCORE_PORT, SDLNet_GetError());
}
}
else {
fprintf (stderr, "SDLNet_UDP_Send(): %s\n", SDLNet_GetError());
}
}
#endif
void score_init (Score* score, Args* args, int caveseed, int monstal)
{
if (args == NULL)
return;
memset (score, 0, sizeof(Score));
char cave9_home[FILENAME_MAX];
char* home = getenv("HOME");
if (home != NULL) {
sprintf (cave9_home, "%s/.cave9", home);
mkdir (
cave9_home
#ifndef _WIN32 // XXX no mode on win32
, 0755
#endif
);
}
else {
fprintf (stderr,
"HOME environment variable not set, using '%s' to save\n",
bin_path);
strncpy(cave9_home, bin_path, FILENAME_MAX-1);
cave9_home[FILENAME_MAX-1] = '\0';
}
size_t len = strlen(cave9_home) + strlen("/") + strlen(SCORE_FILE) + 1;
score->filename = malloc (len);
snprintf (score->filename, len, "%s/%s", cave9_home, SCORE_FILE);
assert (score->filename != NULL);
const char* paths[] = { "", ".", "~/.cave9", NULL };
const char* filename = find_file (SCORE_FILE, paths, false);
score->local = 0;
score->caveseed = caveseed;
score->monstal = monstal;
if(filename != NULL) {
FILE* fp = fopen (filename, "r");
if (fp != NULL) {
int fseed = -1;
int fmonstal = 0;
int fscore = 0;
while(!(fseed == score->caveseed && fmonstal == score->monstal) && !feof(fp))
{
fscanf (fp, "%11d:%2d:%11d ", &fseed, &fmonstal, &fscore);
}
if(fseed == caveseed && fmonstal == monstal)
score->local = fscore;
fclose (fp);
}
}
#ifdef GLOBAL_SCORE
score_net_init (score, args->server, args->port);
#endif
}
void score_finish (Score* score)
{
#ifdef GLOBAL_SCORE
score_net_finish (score);
#endif
free (score->filename);
score->filename = NULL;
}
void score_update (Score* score, int new_score, bool is_global)
{
if (new_score > score->session)
score->session = new_score;
if (is_global) {
if (new_score > score->local) {
score->local = new_score;
FILE* fp = fopen (score->filename, "r+");
bool readwrite = true;
if (fp == NULL)
{
// file didn't exist yet, we need to create an empty one
fp = fopen (score->filename, "w");
readwrite = false;
}
if (fp == NULL) {
perror ("failed to open score file");
} else {
int fseed = -1;
int fmonstal = 0;
int fscore = 0;
bool found = false;
if (readwrite)
{
while (!feof(fp) && !found)
{
fscanf (fp, "%11d:%2d:%11d", &fseed, &fmonstal, &fscore);
if (fseed == score->caveseed && fmonstal == score->monstal)
{
if (fscore <= score->local)
{
fseek(fp, -11, SEEK_CUR);
fprintf(fp, "%011d", score->local);
}
found = true;
}
}
}
if (!found || !readwrite)
{
fprintf(fp, "%011d:%02d:%011d\n", score->caveseed, score->monstal, score->local);
}
fclose (fp);
}
}
int new_global = MAX(new_score, score->local);
if (new_global > score->global) {
score->global = new_global;
#ifdef GLOBAL_SCORE
score_net_update (score);
#endif
}
}
}
// vim600:fdm=syntax:fdn=1: