Crossfire Server, Branch 1.12
R12190
|
00001 /*****************************************************************************/ 00002 /* Newspaper plugin version 1.0 alpha. */ 00003 /* Contact: */ 00004 /*****************************************************************************/ 00005 /* That code is placed under the GNU General Public Licence (GPL) */ 00006 /* (C)2007 by Weeger Nicolas (Feel free to deliver your complaints) */ 00007 /*****************************************************************************/ 00008 /* CrossFire, A Multiplayer game for X-windows */ 00009 /* */ 00010 /* Copyright (C) 2000 Mark Wedel */ 00011 /* Copyright (C) 1992 Frank Tore Johansen */ 00012 /* */ 00013 /* This program is free software; you can redistribute it and/or modify */ 00014 /* it under the terms of the GNU General Public License as published by */ 00015 /* the Free Software Foundation; either version 2 of the License, or */ 00016 /* (at your option) any later version. */ 00017 /* */ 00018 /* This program is distributed in the hope that it will be useful, */ 00019 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 00020 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 00021 /* GNU General Public License for more details. */ 00022 /* */ 00023 /* You should have received a copy of the GNU General Public License */ 00024 /* along with this program; if not, write to the Free Software */ 00025 /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 00026 /* */ 00027 /*****************************************************************************/ 00028 00029 /* First let's include the header file needed */ 00030 00031 #include <cfnewspaper.h> 00032 #include <stdarg.h> 00033 #ifndef __CEXTRACT__ 00034 #include <cfnewspaper_proto.h> 00035 #endif 00036 #include <sqlite3.h> 00037 00038 f_plug_api gethook; 00039 00040 f_plug_api registerGlobalEvent; 00041 00042 f_plug_api unregisterGlobalEvent; 00043 00044 f_plug_api reCmp; 00045 00046 static sqlite3 *logger_database; 00047 00048 static sqlite3 *newspaper_database; 00049 00050 static void do_sql(const char *sql, sqlite3 *base) { 00051 int err; 00052 char *msg; 00053 00054 if (!base) 00055 return; 00056 00057 err = sqlite3_exec(base, sql, NULL, NULL, &msg); 00058 if (err != SQLITE_OK) { 00059 cf_log(llevError, " [%s] error: %d [%s] for sql = %s\n", PLUGIN_NAME, err, msg, sql); 00060 sqlite3_free(msg); 00061 } 00062 } 00063 00064 static int get_living_id(object *living) { 00065 char **line; 00066 char *sql; 00067 int nrow, ncolumn, id; 00068 00069 if (living->type == PLAYER) 00070 sql = sqlite3_mprintf("select liv_id from living where liv_name='%q' and liv_is_player = 1", living->name); 00071 else 00072 sql = sqlite3_mprintf("select liv_id from living where liv_name='%q' and liv_is_player = 0 and liv_level = %d", living->name, living->level); 00073 sqlite3_get_table(logger_database, sql, &line, &nrow, &ncolumn, NULL); 00074 /* printf("get_table: nrow = %d, ncolumn = %d\n", nrow, ncolumn); */ 00075 if (nrow > 0) 00076 id = atoi(line[ncolumn]); 00077 else { 00078 sqlite3_free(sql); 00079 sql = sqlite3_mprintf("insert into living(liv_name, liv_is_player, liv_level) values('%q', %d, %d)", living->name, living->type == PLAYER ? 1 : 0, living->level); 00080 do_sql(sql, logger_database); 00081 id = sqlite3_last_insert_rowid(logger_database); 00082 } 00083 sqlite3_free(sql); 00084 sqlite3_free_table(line); 00085 return id; 00086 } 00087 00088 static int get_region_id(region *reg) { 00089 char **line; 00090 char *sql; 00091 int nrow, ncolumn, id; 00092 00093 if (!reg) 00094 return 0; 00095 00096 sql = sqlite3_mprintf("select reg_id from region where reg_name='%q'", reg->name); 00097 sqlite3_get_table(logger_database, sql, &line, &nrow, &ncolumn, NULL); 00098 00099 if (nrow > 0) 00100 id = atoi(line[ncolumn]); 00101 else { 00102 sqlite3_free(sql); 00103 sql = sqlite3_mprintf("insert into region(reg_name) values( '%q' )", reg->name); 00104 do_sql(sql, logger_database); 00105 id = sqlite3_last_insert_rowid(logger_database); 00106 } 00107 sqlite3_free(sql); 00108 sqlite3_free_table(line); 00109 return id; 00110 } 00111 00112 static void format_time(timeofday_t *tod, char *buffer, int size) { 00113 snprintf(buffer, size, "%10d-%2d-%2d %2d:%2d", tod->year, tod->month, tod->day, tod->hour, tod->minute); 00114 } 00115 00116 static int get_time_id(timeofday_t *tod, int create) { 00117 char **line; 00118 char *sql; 00119 int nrow, ncolumn, id = 0; 00120 char date[50]; 00121 00122 format_time(tod, date, 50); 00123 00124 sql = sqlite3_mprintf("select time_id from time where time_time='%q'", date); 00125 sqlite3_get_table(logger_database, sql, &line, &nrow, &ncolumn, NULL); 00126 if (nrow > 0) 00127 id = atoi(line[ncolumn]); 00128 else if (create) { 00129 sqlite3_free(sql); 00130 sql = sqlite3_mprintf("insert into time(time_time) values( '%q' )", date); 00131 do_sql(sql, logger_database); 00132 id = sqlite3_last_insert_rowid(logger_database); 00133 } 00134 sqlite3_free(sql); 00135 sqlite3_free_table(line); 00136 return id; 00137 } 00138 00139 static void read_parameters(void) { 00140 } 00141 00142 CF_PLUGIN int initPlugin(const char *iversion, f_plug_api gethooksptr) { 00143 cf_init_plugin(gethooksptr); 00144 cf_log(llevInfo, "%s init\n", PLUGIN_VERSION); 00145 return 0; 00146 } 00147 00148 CF_PLUGIN void *getPluginProperty(int *type, ...) { 00149 va_list args; 00150 const char *propname; 00151 int size; 00152 char *buf; 00153 00154 va_start(args, type); 00155 propname = va_arg(args, const char *); 00156 00157 if (!strcmp(propname, "Identification")) { 00158 buf = va_arg(args, char *); 00159 size = va_arg(args, int); 00160 va_end(args); 00161 snprintf(buf, size, PLUGIN_NAME); 00162 return NULL; 00163 } 00164 00165 if (!strcmp(propname, "FullName")) { 00166 buf = va_arg(args, char *); 00167 size = va_arg(args, int); 00168 va_end(args); 00169 snprintf(buf, size, PLUGIN_VERSION); 00170 return NULL; 00171 } 00172 00173 va_end(args); 00174 return NULL; 00175 } 00176 00177 CF_PLUGIN int cfnewspaper_runPluginCommand(object *op, char *params) { 00178 return -1; 00179 } 00180 00181 CF_PLUGIN void *cfnewspaper_globalEventListener(int *type, ...) { 00182 va_list args; 00183 static int rv = 0; 00184 int event_code; 00185 00186 va_start(args, type); 00187 event_code = va_arg(args, int); 00188 00189 switch (event_code) { 00190 } 00191 va_end(args); 00192 00193 return &rv; 00194 } 00195 00196 CF_PLUGIN int postInitPlugin(void) { 00197 char path[500]; 00198 const char *dir; 00199 00200 cf_log(llevInfo, "%s post init\n", PLUGIN_VERSION); 00201 00202 dir = cf_get_directory(4); 00203 snprintf(path, 500, "%s/cflogger.db", dir); 00204 00205 if (sqlite3_open(path, &logger_database) != SQLITE_OK) { 00206 cf_log(llevError, " [%s] couldn't connect to logger database!\n", PLUGIN_NAME); 00207 sqlite3_close(logger_database); 00208 logger_database = NULL; 00209 return 0; 00210 } 00211 00212 snprintf(path, 500, "%s/cfnewspaper.db", dir); 00213 if (sqlite3_open(path, &newspaper_database) != SQLITE_OK) { 00214 cf_log(llevError, " [%s] unable to open newspaper database!\n", PLUGIN_NAME); 00215 sqlite3_close(logger_database); 00216 sqlite3_close(newspaper_database); 00217 logger_database = NULL; 00218 newspaper_database = NULL; 00219 return 0; 00220 } 00221 00222 read_parameters(); 00223 00224 return 0; 00225 } 00226 00227 typedef struct paper_properties { 00228 const char *name; 00229 int info_region; 00230 int info_world; 00231 } paper_properties; 00232 00233 static paper_properties default_properties = { 00234 "world newspaper", 00235 0, 00236 1 00237 }; 00238 00239 typedef struct kill_format { 00240 const char *no_player_death; 00241 const char *one_player_death; 00242 const char *many_player_death; 00243 const char *no_monster_death; 00244 const char *one_monster_death; 00245 const char *many_monster_death; 00246 } kill_format; 00247 00248 static paper_properties *get_newspaper(const char *name) { 00249 return &default_properties; 00250 } 00251 00252 static void news_cat(char *buffer, int size, const char *format, ...) { 00253 va_list args; 00254 00255 size -= strlen(buffer)-1; 00256 buffer += strlen(buffer); 00257 00258 va_start(args, format); 00259 vsprintf(buffer, format, args); 00260 va_end(args); 00261 } 00262 00263 static void do_kills(char *buffer, int size, time_t start, time_t end, const char *reg, kill_format *format) { 00264 char *sql; 00265 char **results; 00266 int deaths = 0; 00267 int nrow, ncolumn; 00268 int err; 00269 char *msg; 00270 const char *raw = "select sum(1) as deaths from kill_event inner join living on liv_id = ke_victim_id where liv_is_player = %d and ke_time >= %d and ke_time < %d %s"; 00271 00272 sql = sqlite3_mprintf(raw, 1, start, end, reg); 00273 err = sqlite3_get_table(logger_database, sql, &results, &nrow, &ncolumn, &msg); 00274 if (err != SQLITE_OK) { 00275 cf_log(llevError, " [%s] error: %d [%s] for sql = %s\n", PLUGIN_NAME, err, msg, sql); 00276 sqlite3_free(msg); 00277 } 00278 if (nrow > 0 && results[ncolumn] != NULL) 00279 deaths = atoi(results[ncolumn]); 00280 sqlite3_free_table(results); 00281 00282 if (deaths == 0) 00283 news_cat(buffer, size, format->no_player_death); 00284 else if (deaths == 1) 00285 news_cat(buffer, size, format->one_player_death); 00286 else 00287 news_cat(buffer, size, format->many_player_death, deaths); 00288 news_cat(buffer, size, "\n"); 00289 00290 sql = sqlite3_mprintf(raw, 0, start, end); 00291 err = sqlite3_get_table(logger_database, sql, &results, &nrow, &ncolumn, &msg); 00292 if (err != SQLITE_OK) { 00293 cf_log(llevError, " [%s] error: %d [%s] for sql = %s\n", PLUGIN_NAME, err, msg, sql); 00294 sqlite3_free(msg); 00295 } 00296 if (nrow > 0 && results[ncolumn] != NULL) 00297 deaths = atoi(results[ncolumn]); 00298 sqlite3_free_table(results); 00299 00300 if (deaths == 0) 00301 news_cat(buffer, size, format->no_monster_death); 00302 else if (deaths == 1) 00303 news_cat(buffer, size, format->one_monster_death); 00304 else 00305 news_cat(buffer, size, format->many_monster_death, deaths); 00306 news_cat(buffer, size, "\n"); 00307 } 00308 00309 static void do_region_kills(region *reg, char *buffer, int size, time_t start, time_t end) { 00310 kill_format f; 00311 char where[50]; 00312 int region_id; 00313 00314 f.no_player_death = "No player died."; 00315 f.one_player_death = "Only one player died, May Fido(tm) Have Mercy."; 00316 f.many_player_death = "Monsters were busy, %d players died."; 00317 f.no_monster_death = "No monster was killed, players were lazy around here."; 00318 f.one_monster_death = "One poor monster was killed."; 00319 f.many_monster_death = "Players tried hard to kill monsters, with %d victims."; 00320 00321 region_id = get_region_id(reg); 00322 snprintf(where, 50, "and map_reg_id = %d", region_id); 00323 00324 do_kills(buffer, size, start, end, where, &f); 00325 } 00326 00327 static void do_region(region *reg, char *buffer, int size, time_t start, time_t end) { 00328 news_cat(buffer, size, "--- local %s news ---\n", reg->name); 00329 do_region_kills(reg, buffer, size, start, end); 00330 news_cat(buffer, size, "\n\n"); 00331 } 00332 00333 static void do_world_kills(char *buffer, int size, time_t start, time_t end) { 00334 kill_format f; 00335 00336 f.no_player_death = "No player died at all."; 00337 f.one_player_death = "Only one player died in the whole world, May Fido(tm) Have Mercy."; 00338 f.many_player_death = "Monsters all around the world were busy, %d players died."; 00339 f.no_monster_death = "No monster was killed at all, players must be tired!"; 00340 f.one_monster_death = "One poor monster was killed in the whole, too bad for it."; 00341 f.many_monster_death = "Bad day for monsters, with %d dead in their ranks."; 00342 do_kills(buffer, size, start, end, "", &f); 00343 } 00344 00345 static void do_world(char *buffer, int size, time_t start, time_t end) { 00346 news_cat(buffer, size, "--- worldnews section ---\n"); 00347 do_world_kills(buffer, size, start, end); 00348 news_cat(buffer, size, "\n\n"); 00349 } 00350 00351 static void get_newspaper_content(object *paper, paper_properties *properties, region *reg) { 00352 char contents[5000]; 00353 char *sql; 00354 char **results; 00355 char date[50]; 00356 int nrow, ncolumn; 00357 time_t start, end; 00358 timeofday_t tod; 00359 int err; 00360 char *msg; 00361 00362 start = 0; 00363 time(&end); 00364 00365 cf_get_time(&tod); 00366 format_time(&tod, date, 50); 00367 00368 sql = sqlite3_mprintf("select * from time where time_ingame < '%q' order by time_ingame desc", date); 00369 err = sqlite3_get_table(logger_database, sql, &results, &nrow, &ncolumn, &msg); 00370 if (err != SQLITE_OK) { 00371 cf_log(llevError, " [%s] error: %d [%s] for sql = %s\n", PLUGIN_NAME, err, msg, sql); 00372 sqlite3_free(msg); 00373 } 00374 if (nrow > 1 && results[ncolumn+1] != NULL) { 00375 end = atol(results[ncolumn+1]); 00376 if (nrow > 1 && results[ncolumn+2] != NULL) 00377 start = atol(results[ncolumn+2]); 00378 } 00379 00380 contents[0] = '\0'; 00381 00382 if (properties->info_region) 00383 do_region(reg, contents, 5000, start, end); 00384 00385 if (properties->info_world) 00386 do_world(contents, 5000, start, end); 00387 00388 cf_object_set_string_property(paper, CFAPI_OBJECT_PROP_MESSAGE, contents); 00389 } 00390 00391 CF_PLUGIN void *eventListener(int *type, ...) { 00392 static int rv = 0; 00393 va_list args; 00394 object *who; 00395 int event_code; 00396 object *activator; 00397 object *third; 00398 object *event; 00399 char *buf; 00400 int fix; 00401 object *newspaper; 00402 paper_properties *paper; 00403 region *reg; 00404 00405 va_start(args, type); 00406 who = va_arg(args, object *); 00407 /*event_code = va_arg(args, int);*/ 00408 activator = va_arg(args, object *); 00409 third = va_arg(args, object *); 00410 buf = va_arg(args, char *); 00411 fix = va_arg(args, int); 00412 /*buf = va_arg(args, char *);*/ 00413 event = va_arg(args, object *); 00414 event_code = event->subtype; 00415 00416 va_end(args); 00417 00418 if (event_code != EVENT_APPLY) 00419 return &rv; 00420 00421 paper = get_newspaper(event->slaying); 00422 00423 newspaper = cf_create_object_by_name("scroll"); 00424 00425 cf_object_set_string_property(newspaper, CFAPI_OBJECT_PROP_NAME, paper->name); 00426 cf_object_set_string_property(newspaper, CFAPI_OBJECT_PROP_NAME_PLURAL, paper->name); 00427 00428 if (activator->map) 00429 reg = cf_map_get_region_property(activator->map, CFAPI_MAP_PROP_REGION); 00430 else 00431 reg = NULL; 00432 00433 get_newspaper_content(newspaper, paper, reg); 00434 00435 cf_object_insert_object(newspaper, who); 00436 00437 return &rv; 00438 } 00439 00440 CF_PLUGIN int closePlugin(void) { 00441 cf_log(llevInfo, "%s closing.\n", PLUGIN_VERSION); 00442 if (logger_database) { 00443 sqlite3_close(logger_database); 00444 logger_database = NULL; 00445 } 00446 if (newspaper_database) { 00447 sqlite3_close(newspaper_database); 00448 newspaper_database = NULL; 00449 } 00450 return 0; 00451 }