locales: updated fr translation
[neverball] / ball / level.c
index 48f6506..d6cd0a0 100644 (file)
@@ -1,4 +1,4 @@
-/*   
+/*
  * Copyright (C) 2003 Robert Kooima
  *
  * NEVERBALL is  free software; you can redistribute  it and/or modify
 #include <string.h>
 #include <math.h>
 #include <errno.h>
+#include <assert.h>
 
-#include "level.h"
 #include "solid.h"
+#include "config.h"
+#include "level.h"
+#include "set.h"
 
 /*---------------------------------------------------------------------------*/
 
-void score_init_hs(struct score *s, int timer, int coins)
+static void scan_level_attribs(struct level *l, const struct s_file *fp)
 {
     int i;
-    strcpy(s->player[0], "Hard");
-    strcpy(s->player[1], "Medium");
-    strcpy(s->player[2], "Easy");
-    strcpy(s->player[3], "");
-    for (i = 0; i < NSCORE+1; i++)
+
+    int have_goal = 0, have_time = 0;
+    int need_bt_easy = 0, need_ug_easy = 0, need_mc_easy = 0;
+
+    for (i = 0; i < fp->dc; i++)
     {
-       s->timer[i] = timer;
-       s->coins[i] = coins;
+        char *k = fp->av + fp->dv[i].ai;
+        char *v = fp->av + fp->dv[i].aj;
+
+        if (strcmp(k, "message") == 0)
+            strncpy(l->message, v, MAXSTR);
+        else if (strcmp(k, "song") == 0)
+            strncpy(l->song, v, PATHMAX);
+        else if (strcmp(k, "shot") == 0)
+            strncpy(l->shot, v, PATHMAX);
+        else if (strcmp(k, "goal") == 0)
+        {
+            l->goal = atoi(v);
+            have_goal = 1;
+        }
+        else if (strcmp(k, "time") == 0)
+        {
+            l->time = atoi(v);
+            have_time = 1;
+        }
+        else if (strcmp(k, "time_hs") == 0)
+        {
+            switch (sscanf(v, "%d %d %d",
+                           &l->score.best_times.timer[0],
+                           &l->score.best_times.timer[1],
+                           &l->score.best_times.timer[2]))
+            {
+            case 2: need_bt_easy = 1; break;
+            case 3:                   break;
+
+            default:
+                /* TODO, complain loudly? */
+                break;
+            }
+        }
+        else if (strcmp(k, "goal_hs") == 0)
+        {
+            switch (sscanf(v, "%d %d %d",
+                           &l->score.unlock_goal.timer[0],
+                           &l->score.unlock_goal.timer[1],
+                           &l->score.unlock_goal.timer[2]))
+            {
+            case 2: need_ug_easy = 1; break;
+            case 3:                   break;
+
+            default:
+                /* TODO, complain loudly? */
+                break;
+            }
+        }
+        else if (strcmp(k, "coin_hs") == 0)
+        {
+            switch (sscanf(v, "%d %d %d",
+                           &l->score.most_coins.coins[0],
+                           &l->score.most_coins.coins[1],
+                           &l->score.most_coins.coins[2]))
+            {
+            case 2: need_mc_easy = 1; break;
+            case 3:                   break;
+
+            default:
+                /* TODO, complain loudly? */
+                break;
+            }
+        }
+        else if (strcmp(k, "version") == 0)
+            strncpy(l->version, v, MAXSTR);
+        else if (strcmp(k, "author") == 0)
+            strncpy(l->author, v, MAXSTR);
+        else if (strcmp(k, "bonus") == 0)
+            l->is_bonus = atoi(v) ? 1 : 0;
     }
-}
 
-/*---------------------------------------------------------------------------*/
+    if (have_goal && need_mc_easy)
+        l->score.most_coins.coins[2] = l->goal;
 
-static int level_scan_metadata(struct level *l, char * av)
-{
-#define CASE(x) (strcmp((x), c) == 0)
-    char *c    = av;
-    char *stop = av + strlen(av);
-    char *v, *e;
-    while (c < stop)
+    if (have_time)
     {
-       /* look for the start of the value */
-       v = strchr(c, '=');
-       if (v==NULL)
-           return 0;
-       *v = '\0';
-       v++;
-       
-       /* look the end of the value */
-       e = strchr(v, '\n');
-       if (e==NULL)
-           return 0;
-       *e = '\0';
-       e ++;
-
-       /* test metadata */
-       if (CASE("message"))
-           strcpy(l->message, v);
-       else if (CASE("back"))
-           strcpy(l->back, v);
-       else if (CASE("song"))
-           strcpy(l->song, v);
-       else if (CASE("grad"))
-           strcpy(l->grad, v);
-       else if (CASE("shot"))
-           strcpy(l->shot, v);
-       else if (CASE("goal"))
-       {
-           l->goal = atoi(v);
-           l->coin_score.coins[2] = l->goal;
-       }
-       else if (CASE("time"))
-       {
-           l->time = atoi(v);
-           l->time_score.timer[2] = l->time;
-           l->goal_score.timer[2] = l->time;
-       }
-       else if (CASE("time_hs"))
-           sscanf(v, "%d %d",
-                   &l->time_score.timer[0],
-                   &l->time_score.timer[1]);
-       else if (CASE("goal_hs"))
-           sscanf(v, "%d %d",
-                   &l->goal_score.timer[0],
-                   &l->goal_score.timer[1]);
-       else if (CASE("coin_hs"))
-           sscanf(v, "%d %d",
-                   &l->coin_score.coins[0],
-                   &l->coin_score.coins[1]);
-       else if (CASE("levelname"))
-           strcpy(l->name, v);
-       else if (CASE("version"))
-           l->version = atoi(v);
-       else if (CASE("author"))
-           strcpy(l->author, v);
-       else if (CASE("special"))
-           l->is_bonus = atoi(v);
-       /*else
-           fprintf(stderr, "File %s, ignore %s metadata.\n", l->file, c);*/
-
-       c = e;
+        if (need_bt_easy)
+            l->score.best_times.timer[2] = l->time;
+        if (need_ug_easy)
+            l->score.unlock_goal.timer[2] = l->time;
     }
-    return 1;
 }
 
 int level_load(const char *filename, struct level *level)
-/* Load the sol file 'filename' and fill the 'level' structure
- * return 1 on success, 0 on error */
 {
-    struct s_file sol; /* The solid file data */
+    struct s_file sol;
+
+    int money;
     int i;
-    int money; /* sum of coin value */
-   
-    /* raz level */
-    memset(level, 0, sizeof(struct level));
-    
-    memset(&sol, 0, sizeof(sol));
-
-    /* Try to load the sol file */
-    if (!sol_load_only_file(&sol, filename))
+
+    memset(level, 0, sizeof (struct level));
+    memset(&sol,  0, sizeof (sol));
+
+#define format \
+    L_("Error while loading level file '%s': %s\n")
+#define default_error \
+    L_("Not a valid level file")
+
+    if (!sol_load_only_head(&sol, config_data(filename)))
     {
-       fprintf(stderr, "Error while loading level file '%s': ", filename);
-        if (errno)
-          perror(NULL);
-       else
-          fprintf(stderr, _("Not a valid level file\n"));
-       return 0;
+        const char *error = errno ? strerror(errno) : default_error;
+        fprintf(stderr, format, filename, error);
+        return 0;
     }
 
-    /* Set filename */
-    strcpy(level->file, filename);
-    
-    /* Init hs with default values */
-    score_init_hs(&level->time_score, 59999, 0);
-    score_init_hs(&level->goal_score, 59999, 0);
-    score_init_hs(&level->coin_score, 59999, 0);
+#undef format
+#undef default_error
+
+    strncpy(level->file, filename, PATHMAX - 1);
+
+    score_init_hs(&level->score.best_times, 59999, 0);
+    score_init_hs(&level->score.unlock_goal, 59999, 0);
+    score_init_hs(&level->score.most_coins, 59999, 0);
 
-    /* Compute money and default max money */
     money = 0;
-    for (i = 0; i < sol.cc; i++)
-       money += sol.cv[i].n;
-    level->coin_score.coins[0] = money;
-    
-    /* Scan sol metadata */
-    if (sol.ac > 0)
-        level_scan_metadata(level, sol.av);
+
+    for (i = 0; i < sol.hc; i++)
+        if (sol.hv[i].t == ITEM_COIN)
+            money += sol.hv[i].n;
+
+    level->score.most_coins.coins[0] = money;
+
+    scan_level_attribs(level, &sol);
 
     /* Compute initial hs default values */
-#define HOP(t, c) if (t[2] c t[0]) t[0] = t[1] = t[2]; else if (t[2] c t[1]) t[1] = (t[0] + t[2]) / 2
-    HOP(level->time_score.timer, <=);
-    HOP(level->goal_score.timer, <=);
-    HOP(level->coin_score.coins, >=);
 
-    /* Free the sol structure, no more needed */    
+#define HOP(t, c) \
+    if (t[2] c t[0]) \
+        t[0] = t[1] = t[2]; \
+    else if (t[2] c t[1]) \
+        t[1] = (t[0] + t[2]) / 2
+
+    HOP(level->score.best_times.timer, <=);
+    HOP(level->score.unlock_goal.timer, <=);
+    HOP(level->score.most_coins.coins, >=);
+
     sol_free(&sol);
 
     return 1;
 }
 
-/*---------------------------------------------------------------------------*/
-
-void level_dump_info(const struct level *l)
-/* This function dump the info of a demo structure
- * It's only a function for debugging, no need of I18N */
+void level_dump(const struct level *l)
 {
     printf("filename:        %s\n"
-          "name:            %s\n"
-          "version:         %d\n"
-          "author:          %s\n"
-          "time limit:      %d\n"
-          "goal count:      %d\n"
-          "time hs:         %d %d %d\n"
-          "goal hs:         %d %d %d\n"
-          "coin hs:         %d %d %d\n"
-          "message:         %s\n"
-           "background:      %s\n"
-          "gradiant:        %s\n"
-          "screenshot:      %s\n"
-          "song:            %s\n",
-          l->file, l->name, l->version, l->author,
-          l->time, l->goal,
-          l->time_score.timer[0],
-          l->time_score.timer[1],
-          l->time_score.timer[2],
-          l->goal_score.timer[0],
-          l->goal_score.timer[1],
-          l->goal_score.timer[2],
-          l->coin_score.coins[0],
-          l->coin_score.coins[1],
-          l->coin_score.coins[2],
-          l->message, l->back, l->grad, l->shot, l->song);
+           "version:         %s\n"
+           "author:          %s\n"
+           "time limit:      %d\n"
+           "goal count:      %d\n"
+           "time hs:         %d %d %d\n"
+           "goal hs:         %d %d %d\n"
+           "coin hs:         %d %d %d\n"
+           "message:         %s\n"
+           "screenshot:      %s\n"
+           "song:            %s\n",
+           l->file,
+           l->version,
+           l->author,
+           l->time,
+           l->goal,
+           l->score.best_times.timer[0],
+           l->score.best_times.timer[1],
+           l->score.best_times.timer[2],
+           l->score.unlock_goal.timer[0],
+           l->score.unlock_goal.timer[1],
+           l->score.unlock_goal.timer[2],
+           l->score.most_coins.coins[0],
+           l->score.most_coins.coins[1],
+           l->score.most_coins.coins[2],
+           l->message,
+           l->shot,
+           l->song);
 }
 
 /*---------------------------------------------------------------------------*/
 
-const char * mode_to_str(int m)
+int  level_exists(int i)
 {
-    switch (m)
-    {
-    case MODE_CHALLENGE: return _("Challenge");
-    case MODE_NORMAL:    return _("Normal");
-    case MODE_PRACTICE:  return _("Practice");
-    case MODE_SINGLE:    return _("Single");
-    default:             return "???";
-    }
+    return set_level_exists(curr_set(), i);
+}
+
+void level_open(int i)
+{
+    if (level_exists(i))
+        get_level(i)->is_locked = 0;
+}
+
+int  level_opened(int i)
+{
+    return level_exists(i) && !get_level(i)->is_locked;
+}
+
+void level_complete(int i)
+{
+    if (level_exists(i))
+        get_level(i)->is_completed = 1;
+}
+
+int  level_completed(int i)
+{
+    return level_exists(i) && get_level(i)->is_completed;
+}
+
+int  level_time (int i)
+{
+    assert(level_exists(i));
+    return get_level(i)->time;
+}
+
+int  level_goal (int i)
+{
+    assert(level_exists(i));
+    return get_level(i)->goal;
+}
+
+int  level_bonus(int i)
+{
+    return level_exists(i) && get_level(i)->is_bonus;
+}
+
+const char *level_shot(int i)
+{
+    return level_exists(i) ? get_level(i)->shot : NULL;
+}
+
+const char *level_file(int i)
+{
+    return level_exists(i) ? get_level(i)->file : NULL;
+}
+
+const char *level_name(int i)
+{
+    return level_exists(i) ? get_level(i)->name : NULL;
+}
+
+const char *level_msg(int i)
+{
+    if (level_exists(i) && strlen(get_level(i)->message) > 0)
+        return _(get_level(i)->message);
+
+    return NULL;
 }
 
 /*---------------------------------------------------------------------------*/
 
-const char * state_to_str(int m)
+int level_score_update(int level,
+                       int timer,
+                       int coins,
+                       int *time_rank,
+                       int *goal_rank,
+                       int *coin_rank)
 {
-    switch (m)
-    {
-    case GAME_NONE:    return _("Aborted");
-    case GAME_TIME:    return _("Time-out");
-    case GAME_SPEC:
-    case GAME_GOAL:    return _("Success");
-    case GAME_FALL:    return _("Fall-out");
-    default:           return "???";
-    }
+    struct level *l = get_level(level);
+    char player[MAXSTR] = "";
+
+    config_get_s(CONFIG_PLAYER, player, MAXSTR);
+
+    if (time_rank)
+        *time_rank = score_time_insert(&l->score.best_times,
+                                       player, timer, coins);
+
+    if (goal_rank)
+        *goal_rank = score_time_insert(&l->score.unlock_goal,
+                                       player, timer, coins);
+
+    if (coin_rank)
+        *coin_rank = score_coin_insert(&l->score.most_coins,
+                                       player, timer, coins);
+
+    if ((time_rank && *time_rank < 3) ||
+        (goal_rank && *goal_rank < 3) ||
+        (coin_rank && *coin_rank < 3))
+        return 1;
+    else
+        return 0;
+}
+
+void level_rename_player(int level,
+                         int time_rank,
+                         int goal_rank,
+                         int coin_rank,
+                         const char *player)
+{
+    struct level *l = get_level(level);
+
+    strncpy(l->score.best_times.player [time_rank], player, MAXNAM);
+    strncpy(l->score.unlock_goal.player[goal_rank], player, MAXNAM);
+    strncpy(l->score.most_coins.player [coin_rank], player, MAXNAM);
 }
 
 /*---------------------------------------------------------------------------*/
+