|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <global.h> 00031 00034 typedef struct scr 00035 { 00037 char name[BIG_NAME]; 00038 00040 char title[BIG_NAME]; 00041 00043 char killer[BIG_NAME]; 00044 00046 char maplevel[MAX_BUF]; 00047 00049 uint64 exp; 00050 00052 int maxhp, maxsp, maxgrace; 00053 00055 int position; 00056 } score; 00057 00060 typedef struct 00061 { 00063 char fname[MAX_BUF]; 00064 00066 score entry[HIGHSCORE_LENGTH]; 00067 } score_table; 00068 00071 static score_table hiscore_table; 00072 00078 static void put_score(const score *sc, char *buf, int size) 00079 { 00080 snprintf(buf, size, "%s:%s:%"FMT64U":%s:%s:%d:%d:%d", sc->name, sc->title, sc->exp, sc->killer, sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace); 00081 } 00082 00086 static void hiscore_save(const score_table *table) 00087 { 00088 FILE *fp; 00089 size_t i; 00090 char buf[MAX_BUF]; 00091 00092 LOG(llevDebug, "Writing highscore file %s\n", table->fname); 00093 fp = fopen(table->fname, "w"); 00094 00095 if (!fp) 00096 { 00097 LOG(llevBug, "Cannot create highscore file %s: %s\n", table->fname, strerror_local(errno)); 00098 return; 00099 } 00100 00101 for (i = 0; i < HIGHSCORE_LENGTH; i++) 00102 { 00103 if (table->entry[i].name[0] == '\0') 00104 { 00105 break; 00106 } 00107 00108 put_score(&table->entry[i], buf, sizeof(buf)); 00109 fprintf(fp, "%s\n", buf); 00110 } 00111 00112 if (ferror(fp)) 00113 { 00114 LOG(llevBug, "Cannot write to highscore file %s: %s\n", table->fname, strerror_local(errno)); 00115 fclose(fp); 00116 } 00117 else if (fclose(fp) != 0) 00118 { 00119 LOG(llevBug, "Cannot write to highscore file %s: %s\n", table->fname, strerror_local(errno)); 00120 } 00121 } 00122 00129 static int get_score(char *bp, score *sc) 00130 { 00131 char *cp, *tmp[8]; 00132 00133 cp = strchr(bp, '\n'); 00134 00135 if (cp) 00136 { 00137 *cp = '\0'; 00138 } 00139 00140 if (split_string(bp, tmp, 8, ':') != 8) 00141 { 00142 return 0; 00143 } 00144 00145 strncpy(sc->name, tmp[0], sizeof(sc->name)); 00146 sc->name[sizeof(sc->name) - 1] = '\0'; 00147 00148 strncpy(sc->title, tmp[1], sizeof(sc->title)); 00149 sc->title[sizeof(sc->title) - 1] = '\0'; 00150 00151 sscanf(tmp[2], "%"FMT64U, &sc->exp); 00152 00153 strncpy(sc->killer, tmp[3], sizeof(sc->killer)); 00154 sc->killer[sizeof(sc->killer) - 1] = '\0'; 00155 00156 strncpy(sc->maplevel, tmp[4], sizeof(sc->maplevel)); 00157 sc->maplevel[sizeof(sc->maplevel) - 1] = '\0'; 00158 00159 sscanf(tmp[5], "%d", &sc->maxhp); 00160 sscanf(tmp[6], "%d", &sc->maxsp); 00161 sscanf(tmp[7], "%d", &sc->maxgrace); 00162 return 1; 00163 } 00164 00171 static char *draw_one_high_score(const score *sc, char *buf, size_t size) 00172 { 00173 if (sc->killer[0] == '\0') 00174 { 00175 snprintf(buf, size, "<green>%3d</green> %s <green>%s</green> the %s (%s) <%d><%d><%d>.", sc->position, format_number_comma(sc->exp), sc->name, sc->title, sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace); 00176 } 00177 else 00178 { 00179 const char *s1, *s2; 00180 00181 if (!strcmp(sc->killer, "left")) 00182 { 00183 s1 = sc->killer; 00184 s2 = "the game"; 00185 } 00186 else 00187 { 00188 s1 = "was killed by"; 00189 s2 = sc->killer; 00190 } 00191 00192 snprintf(buf, size, "<green>%3d</green> %s <green>%s</green> the %s %s %s on map %s <%d><%d><%d>.", sc->position, format_number_comma(sc->exp), sc->name, sc->title, s1, s2, sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace); 00193 } 00194 00195 return buf; 00196 } 00197 00204 static void add_score(score_table *table, score *new_score, score *old_score) 00205 { 00206 size_t i; 00207 00208 new_score->position = HIGHSCORE_LENGTH + 1; 00209 memset(old_score, 0, sizeof(*old_score)); 00210 old_score->position = -1; 00211 00212 /* Find existing entry by name */ 00213 for (i = 0; i < HIGHSCORE_LENGTH; i++) 00214 { 00215 if (table->entry[i].name[0] == '\0') 00216 { 00217 table->entry[i] = *new_score; 00218 table->entry[i].position = i + 1; 00219 break; 00220 } 00221 00222 if (strcmp(new_score->name, table->entry[i].name) == 0) 00223 { 00224 *old_score = table->entry[i]; 00225 00226 if (table->entry[i].exp <= new_score->exp) 00227 { 00228 table->entry[i] = *new_score; 00229 table->entry[i].position = i + 1; 00230 } 00231 00232 break; 00233 } 00234 } 00235 00236 /* Entry for unknown name */ 00237 if (i >= HIGHSCORE_LENGTH) 00238 { 00239 /* New exp is less than lowest hiscore entry => drop */ 00240 if (new_score->exp < table->entry[i - 1].exp) 00241 { 00242 return; 00243 } 00244 00245 /* New exp is not less than lowest hiscore entry => add */ 00246 i--; 00247 table->entry[i] = *new_score; 00248 table->entry[i].position = i + 1; 00249 } 00250 00251 /* Move entry to correct position */ 00252 while (i > 0 && new_score->exp >= table->entry[i - 1].exp) 00253 { 00254 score tmp; 00255 00256 tmp = table->entry[i - 1]; 00257 table->entry[i - 1] = table->entry[i]; 00258 table->entry[i] = tmp; 00259 00260 table->entry[i - 1].position = i; 00261 table->entry[i].position = i + 1; 00262 00263 i--; 00264 } 00265 00266 new_score->position = table->entry[i].position; 00267 hiscore_save(table); 00268 } 00269 00273 static void hiscore_load(score_table *table) 00274 { 00275 FILE *fp; 00276 size_t i = 0; 00277 00278 fp = fopen(table->fname, "r"); 00279 00280 if (!fp) 00281 { 00282 if (errno == ENOENT) 00283 { 00284 LOG(llevDebug, "Highscore file %s does not exist\n", table->fname); 00285 } 00286 else 00287 { 00288 LOG(llevBug, "Cannot open highscore file %s: %s\n", table->fname, strerror_local(errno)); 00289 } 00290 } 00291 else 00292 { 00293 LOG(llevDebug, "Reading highscore file %s\n", table->fname); 00294 00295 while (i < HIGHSCORE_LENGTH) 00296 { 00297 char buf[MAX_BUF]; 00298 00299 if (!fgets(buf, sizeof(buf), fp)) 00300 { 00301 break; 00302 } 00303 00304 if (!get_score(buf, &table->entry[i])) 00305 { 00306 break; 00307 } 00308 00309 table->entry[i].position = i + 1; 00310 i++; 00311 } 00312 00313 fclose(fp); 00314 } 00315 00316 while (i < HIGHSCORE_LENGTH) 00317 { 00318 memset(&table->entry[i], 0, sizeof(table->entry[i])); 00319 table->entry[i].position = i + 1; 00320 i++; 00321 } 00322 } 00323 00326 void hiscore_init() 00327 { 00328 snprintf(hiscore_table.fname, sizeof(hiscore_table.fname), "%s/%s", settings.localdir, HIGHSCORE); 00329 hiscore_load(&hiscore_table); 00330 } 00331 00338 void hiscore_check(object *op, int quiet) 00339 { 00340 score new_score, old_score; 00341 char bufscore[MAX_BUF], race[MAX_BUF]; 00342 const char *message; 00343 00344 if (!op->stats.exp) 00345 { 00346 return; 00347 } 00348 00349 if (QUERY_FLAG(op, FLAG_WAS_WIZ)) 00350 { 00351 if (!quiet) 00352 { 00353 new_draw_info(0, COLOR_WHITE, op, "Since you have been in wizard mode, you can't enter the high-score list."); 00354 } 00355 00356 return; 00357 } 00358 00359 strncpy(new_score.name, op->name, sizeof(new_score.name)); 00360 new_score.name[sizeof(new_score.name) - 1] = '\0'; 00361 00362 strncpy(new_score.title, player_get_race_class(op, race, sizeof(race)), sizeof(new_score.title)); 00363 new_score.title[sizeof(new_score.title) - 1] = '\0'; 00364 00365 strncpy(new_score.killer, CONTR(op)->killer, sizeof(new_score.killer)); 00366 new_score.killer[sizeof(new_score.killer) - 1] = '\0'; 00367 00368 new_score.exp = calculate_total_exp(op); 00369 00370 if (op->map == NULL) 00371 { 00372 *new_score.maplevel = '\0'; 00373 } 00374 else 00375 { 00376 size_t i; 00377 00378 strncpy(new_score.maplevel, op->map->name ? op->map->name : op->map->path, sizeof(new_score.maplevel) - 1); 00379 new_score.maplevel[sizeof(new_score.maplevel) - 1] = '\0'; 00380 00381 /* Replace ':' in the map name with ' ' so it doesn't break the loading. */ 00382 for (i = 0; new_score.maplevel[i]; i++) 00383 { 00384 if (new_score.maplevel[i] == ':') 00385 { 00386 new_score.maplevel[i] = ' '; 00387 } 00388 } 00389 } 00390 00391 new_score.maxhp = (int) op->stats.maxhp; 00392 new_score.maxsp = (int) op->stats.maxsp; 00393 new_score.maxgrace = (int) op->stats.maxgrace; 00394 add_score(&hiscore_table, &new_score, &old_score); 00395 00396 /* Everything below here is just related to print messages 00397 * to the player. If quiet is set, we can just return 00398 * now. */ 00399 if (quiet) 00400 { 00401 return; 00402 } 00403 00404 if (old_score.position == -1) 00405 { 00406 if (new_score.position > HIGHSCORE_LENGTH) 00407 { 00408 message = "You didn't enter the highscore list:"; 00409 } 00410 else 00411 { 00412 message = "You entered the highscore list:"; 00413 } 00414 } 00415 else 00416 { 00417 if (new_score.position > HIGHSCORE_LENGTH) 00418 { 00419 message = "You left the highscore list:"; 00420 } 00421 else if (new_score.exp > old_score.exp) 00422 { 00423 message = "You beat your last score:"; 00424 } 00425 else 00426 { 00427 message = "You didn't beat your last score:"; 00428 } 00429 } 00430 00431 new_draw_info(0, COLOR_WHITE, op, message); 00432 00433 if (old_score.position != -1) 00434 { 00435 new_draw_info(0, COLOR_WHITE, op, draw_one_high_score(&old_score, bufscore, sizeof(bufscore))); 00436 } 00437 00438 new_draw_info(0, COLOR_WHITE, op, draw_one_high_score(&new_score, bufscore, sizeof(bufscore))); 00439 } 00440 00447 void hiscore_display(object *op, int max, const char *match) 00448 { 00449 int printed_entries = 0; 00450 size_t j; 00451 00452 new_draw_info(0, COLOR_WHITE, op, "Nr Score Who <max hp><max sp><max grace>"); 00453 00454 for (j = 0; j < HIGHSCORE_LENGTH && hiscore_table.entry[j].name[0] != '\0' && printed_entries < max; j++) 00455 { 00456 char scorebuf[MAX_BUF]; 00457 00458 if (match && !strcasestr_local(hiscore_table.entry[j].name, match) && !strcasestr_local(hiscore_table.entry[j].title, match)) 00459 { 00460 continue; 00461 } 00462 00463 draw_one_high_score(&hiscore_table.entry[j], scorebuf, sizeof(scorebuf)); 00464 printed_entries++; 00465 00466 if (op == NULL) 00467 { 00468 LOG(llevDebug, "%s\n", scorebuf); 00469 } 00470 else 00471 { 00472 new_draw_info(0, COLOR_WHITE, op, scorebuf); 00473 } 00474 } 00475 }
1.7.4