Crossfire Server, Trunk  1.75.0
cfnewspaper.cpp
Go to the documentation of this file.
1 /*****************************************************************************/
2 /* Newspaper plugin version 1.0 alpha. */
3 /* Contact: */
4 /*****************************************************************************/
5 /* That code is placed under the GNU General Public Licence (GPL) */
6 /* (C)2007 by Weeger Nicolas (Feel free to deliver your complaints) */
7 /*****************************************************************************/
8 /* CrossFire, A Multiplayer game for X-windows */
9 /* */
10 /* Copyright (C) 2000 Mark Wedel */
11 /* Copyright (C) 1992 Frank Tore Johansen */
12 /* */
13 /* This program is free software; you can redistribute it and/or modify */
14 /* it under the terms of the GNU General Public License as published by */
15 /* the Free Software Foundation; either version 2 of the License, or */
16 /* (at your option) any later version. */
17 /* */
18 /* This program is distributed in the hope that it will be useful, */
19 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
20 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
21 /* GNU General Public License for more details. */
22 /* */
23 /* You should have received a copy of the GNU General Public License */
24 /* along with this program; if not, write to the Free Software */
25 /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
26 /* */
27 /*****************************************************************************/
28 
29 /* First let's include the header file needed */
30 
31 #include <cfnewspaper.h>
32 #include <stdarg.h>
33 #include <cfnewspaper_proto.h>
34 #include <sqlite3.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <svnversion.h>
38 
40 
42 
44 
46 
48 
49 static sqlite3 *logger_database;
50 
51 static sqlite3 *newspaper_database;
52 
53 static void do_sql(const char *sql, sqlite3 *base) {
54  int err;
55  char *msg;
56 
57  if (!base)
58  return;
59 
60  err = sqlite3_exec(base, sql, NULL, NULL, &msg);
61  if (err != SQLITE_OK) {
62  cf_log(llevError, " [%s] error: %d [%s] for sql = %s\n", PLUGIN_NAME, err, msg, sql);
63  sqlite3_free(msg);
64  }
65 }
66 
67 static int get_region_id(region *reg) {
68  char **line;
69  char *sql;
70  int nrow, ncolumn, id;
71 
72  if (!reg)
73  return 0;
74 
75  sql = sqlite3_mprintf("select reg_id from region where reg_name='%q'", reg->name);
76  sqlite3_get_table(logger_database, sql, &line, &nrow, &ncolumn, NULL);
77 
78  if (nrow > 0)
79  id = atoi(line[ncolumn]);
80  else {
81  sqlite3_free(sql);
82  sql = sqlite3_mprintf("insert into region(reg_name) values( '%q' )", reg->name);
83  do_sql(sql, logger_database);
84  id = sqlite3_last_insert_rowid(logger_database);
85  }
86  sqlite3_free(sql);
87  sqlite3_free_table(line);
88  return id;
89 }
90 
91 static void format_time(timeofday_t *tod, char *buffer, int size) {
92  snprintf(buffer, size, "%10d-%2d-%2d %2d:%2d", tod->year, tod->month, tod->day, tod->hour, tod->minute);
93 }
94 
95 static void read_parameters(void) {
96 }
97 
98 extern "C" int initPlugin(const char *iversion, f_plug_api gethooksptr) {
99  cf_init_plugin(gethooksptr);
100  cf_log(llevInfo, "%s init\n", PLUGIN_VERSION);
101  return 0;
102 }
103 
104 extern "C" void *getPluginProperty(int *type, ...) {
105  va_list args;
106  const char *propname;
107  int size;
108  char *buf;
109 
110  va_start(args, type);
111  propname = va_arg(args, const char *);
112 
113  if (!strcmp(propname, "Identification")) {
114  buf = va_arg(args, char *);
115  size = va_arg(args, int);
116  va_end(args);
117  snprintf(buf, size, PLUGIN_NAME);
118  return NULL;
119  }
120 
121  if (!strcmp(propname, "FullName")) {
122  buf = va_arg(args, char *);
123  size = va_arg(args, int);
124  va_end(args);
125  snprintf(buf, size, PLUGIN_VERSION);
126  return NULL;
127  }
128 
129  va_end(args);
130  return NULL;
131 }
132 
133 extern "C" int cfnewspaper_runPluginCommand(object *op, char *params) {
134  return -1;
135 }
136 
137 extern "C" int cfnewspaper_globalEventListener(int *type, ...) {
138  va_list args;
139  int rv = 0;
140  int event_code;
141 
142  va_start(args, type);
143  event_code = va_arg(args, int);
144 
145  switch (event_code) {
146  }
147  va_end(args);
148 
149  return rv;
150 }
151 
152 extern "C" int postInitPlugin(void) {
153  char path[500];
154  const char *dir;
155 
156  cf_log(llevInfo, "%s post init\n", PLUGIN_VERSION);
157 
158  dir = cf_get_directory(4);
159  snprintf(path, 500, "%s/cflogger.db", dir);
160 
161  if (sqlite3_open(path, &logger_database) != SQLITE_OK) {
162  cf_log(llevError, " [%s] couldn't connect to logger database!\n", PLUGIN_NAME);
163  sqlite3_close(logger_database);
164  logger_database = NULL;
165  return 0;
166  }
167 
168  snprintf(path, 500, "%s/cfnewspaper.db", dir);
169  if (sqlite3_open(path, &newspaper_database) != SQLITE_OK) {
170  cf_log(llevError, " [%s] unable to open newspaper database!\n", PLUGIN_NAME);
171  sqlite3_close(logger_database);
172  sqlite3_close(newspaper_database);
173  logger_database = NULL;
174  newspaper_database = NULL;
175  return 0;
176  }
177 
178  read_parameters();
179 
180  return 0;
181 }
182 
183 typedef struct paper_properties {
184  const char *name;
188 
190  "world newspaper",
191  0,
192  1
193 };
194 
195 typedef struct kill_format {
196  const char *no_player_death;
197  const char *one_player_death;
198  const char *many_player_death;
199  const char *no_monster_death;
200  const char *one_monster_death;
201  const char *many_monster_death;
202 } kill_format;
203 
204 static paper_properties *get_newspaper(const char *name) {
205  return &default_properties;
206 }
207 
208 static void news_cat(char *buffer, int size, const char *format, ...) {
209  va_list args;
210 
211  size -= strlen(buffer)-1;
212  buffer += strlen(buffer);
213 
214  va_start(args, format);
215  vsprintf(buffer, format, args);
216  va_end(args);
217 }
218 
219 static void do_kills(char *buffer, int size, time_t start, time_t end, const char *reg, kill_format *format) {
220  char *sql;
221  char **results;
222  int deaths = 0;
223  int nrow, ncolumn;
224  int err;
225  char *msg;
226  const char *raw_players = "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";
227  const char *raw_monsters = "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";
228 
229  sql = sqlite3_mprintf(raw_players, 1, start, end, reg);
230  err = sqlite3_get_table(logger_database, sql, &results, &nrow, &ncolumn, &msg);
231  sqlite3_free(sql);
232  if (err != SQLITE_OK) {
233  cf_log(llevError, " [%s] error: %d [%s] for sql = %s\n", PLUGIN_NAME, err, msg, sql);
234  sqlite3_free(msg);
235  }
236  if (nrow > 0 && results[ncolumn] != NULL)
237  deaths = atoi(results[ncolumn]);
238  sqlite3_free_table(results);
239 
240  if (deaths == 0)
241  news_cat(buffer, size, format->no_player_death);
242  else if (deaths == 1)
243  news_cat(buffer, size, format->one_player_death);
244  else
245  news_cat(buffer, size, format->many_player_death, deaths);
246  news_cat(buffer, size, "\n");
247 
248  sql = sqlite3_mprintf(raw_monsters, 0, start, end);
249  err = sqlite3_get_table(logger_database, sql, &results, &nrow, &ncolumn, &msg);
250  sqlite3_free(sql);
251  if (err != SQLITE_OK) {
252  cf_log(llevError, " [%s] error: %d [%s] for sql = %s\n", PLUGIN_NAME, err, msg, sql);
253  sqlite3_free(msg);
254  }
255  if (nrow > 0 && results[ncolumn] != NULL)
256  deaths = atoi(results[ncolumn]);
257  sqlite3_free_table(results);
258 
259  if (deaths == 0)
260  news_cat(buffer, size, format->no_monster_death);
261  else if (deaths == 1)
262  news_cat(buffer, size, format->one_monster_death);
263  else
264  news_cat(buffer, size, format->many_monster_death, deaths);
265  news_cat(buffer, size, "\n");
266 }
267 
268 static void do_region_kills(region *reg, char *buffer, int size, time_t start, time_t end) {
269  kill_format f;
270  char where[50];
271  int region_id;
272 
273  f.no_player_death = "No player died.";
274  f.one_player_death = "Only one player died, May Fido(tm) Have Mercy.";
275  f.many_player_death = "Monsters were busy, %d players died.";
276  f.no_monster_death = "No monster was killed, players were lazy around here.";
277  f.one_monster_death = "One poor monster was killed.";
278  f.many_monster_death = "Players tried hard to kill monsters, with %d victims.";
279 
280  region_id = get_region_id(reg);
281  snprintf(where, 50, "and map_reg_id = %d", region_id);
282 
283  do_kills(buffer, size, start, end, where, &f);
284 }
285 
286 static void do_region(region *reg, char *buffer, int size, time_t start, time_t end) {
287  news_cat(buffer, size, "--- local %s news ---\n", reg->name);
288  do_region_kills(reg, buffer, size, start, end);
289  news_cat(buffer, size, "\n\n");
290 }
291 
292 static void do_world_kills(char *buffer, int size, time_t start, time_t end) {
293  kill_format f;
294 
295  f.no_player_death = "No player died at all.";
296  f.one_player_death = "Only one player died in the whole world, May Fido(tm) Have Mercy.";
297  f.many_player_death = "Monsters all around the world were busy, %d players died.";
298  f.no_monster_death = "No monster was killed at all, players must be tired!";
299  f.one_monster_death = "One poor monster was killed in the whole world, too bad for it.";
300  f.many_monster_death = "Bad day for monsters, with %d dead in their ranks.";
301  do_kills(buffer, size, start, end, "", &f);
302 }
303 
304 static void do_world(char *buffer, int size, time_t start, time_t end) {
305  news_cat(buffer, size, "--- worldnews section ---\n");
306  do_world_kills(buffer, size, start, end);
307  news_cat(buffer, size, "\n\n");
308 }
309 
310 static void get_newspaper_content(object *paper, paper_properties *properties, region *reg) {
311  char contents[5000];
312  char *sql;
313  char **results;
314  char date[50];
315  int nrow, ncolumn;
316  time_t start, end;
317  timeofday_t tod;
318  int err;
319  char *msg;
320 
321  start = 0;
322  time(&end);
323 
324  cf_get_time(&tod);
325  format_time(&tod, date, 50);
326 
327  sql = sqlite3_mprintf("select * from time where time_ingame < '%q' order by time_ingame desc", date);
328  err = sqlite3_get_table(logger_database, sql, &results, &nrow, &ncolumn, &msg);
329  sqlite3_free(sql);
330  if (err != SQLITE_OK) {
331  cf_log(llevError, " [%s] error: %d [%s] for sql = %s\n", PLUGIN_NAME, err, msg, sql);
332  sqlite3_free(msg);
333  }
334  if (nrow > 1 && results[ncolumn+1] != NULL) {
335  end = atol(results[ncolumn+1]);
336  if (nrow > 1 && results[ncolumn+2] != NULL)
337  start = atol(results[ncolumn+2]);
338  }
339 
340  contents[0] = '\0';
341 
342  if (properties->info_region)
343  do_region(reg, contents, 5000, start, end);
344 
345  if (properties->info_world)
346  do_world(contents, 5000, start, end);
347 
349 }
350 
351 extern "C" int eventListener(int *type, ...) {
352  int rv = 0;
353  va_list args;
354  object *who;
355  int event_code;
356  object *activator;
357  /*object *third;*/
358  object *event;
359  /*char *buf;*/
360  /*int fix;*/
361  object *newspaper;
362  paper_properties *paper;
363  region *reg;
364 
365  va_start(args, type);
366  who = va_arg(args, object *);
367  /*event_code = va_arg(args, int);*/
368  activator = va_arg(args, object *);
369  /*third =*/ va_arg(args, object *);
370  /*buf =*/ va_arg(args, char *);
371  /*fix =*/ va_arg(args, int);
372  /*buf = va_arg(args, char *);*/
373  event = va_arg(args, object *);
374  event_code = event->subtype;
375 
376  va_end(args);
377 
378  if (event_code != EVENT_APPLY)
379  return rv;
380 
381  paper = get_newspaper(event->slaying);
382 
383  newspaper = cf_create_object_by_name("scroll");
384 
387 
388  if (activator->map)
390  else
391  reg = NULL;
392 
393  get_newspaper_content(newspaper, paper, reg);
394 
395  cf_object_insert_object(newspaper, who);
396 
397  return rv;
398 }
399 
400 extern "C" int closePlugin(void) {
401  cf_log(llevInfo, "%s closing.\n", PLUGIN_VERSION);
402  if (logger_database) {
403  sqlite3_close(logger_database);
404  logger_database = NULL;
405  }
406  if (newspaper_database) {
407  sqlite3_close(newspaper_database);
408  newspaper_database = NULL;
409  }
410  return 0;
411 }
cf_map_get_region_property
region * cf_map_get_region_property(mapstruct *map, int propcode)
Definition: plugin_common.cpp:288
do_world
static void do_world(char *buffer, int size, time_t start, time_t end)
Definition: cfnewspaper.cpp:304
unregisterGlobalEvent
f_plug_api unregisterGlobalEvent
Definition: cfnewspaper.cpp:45
cf_log
void cf_log(LogLevel logLevel, const char *format,...)
Wrapper for LOG().
Definition: plugin_common.cpp:1522
read_parameters
static void read_parameters(void)
Definition: cfnewspaper.cpp:95
paper_properties
struct paper_properties paper_properties
do_sql
static void do_sql(const char *sql, sqlite3 *base)
Definition: cfnewspaper.cpp:53
cf_get_directory
const char * cf_get_directory(int id)
Gets a directory Crossfire uses.
Definition: plugin_common.cpp:1130
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
get_newspaper
static paper_properties * get_newspaper(const char *name)
Definition: cfnewspaper.cpp:204
cfnewspaper_globalEventListener
int cfnewspaper_globalEventListener(int *type,...)
Definition: cfnewspaper.cpp:137
paper_properties
Definition: cfnewspaper.cpp:183
timeofday_t::year
int year
Definition: tod.h:39
eventListener
int eventListener(int *type,...)
Handles an object-related event.
Definition: cfnewspaper.cpp:351
kill_format::no_monster_death
const char * no_monster_death
Definition: cfnewspaper.cpp:199
cf_create_object_by_name
object * cf_create_object_by_name(const char *name)
Wrapper for create_archetype() and create_archetype_by_object_name().
Definition: plugin_common.cpp:1093
SVN_REV
#define SVN_REV
Definition: svnversion.h:2
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
cfnewspaper_runPluginCommand
int cfnewspaper_runPluginCommand(object *op, char *params)
Definition: cfnewspaper.cpp:133
timeofday_t
Represents the ingame time.
Definition: tod.h:38
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
cf_object_set_string_property
void cf_object_set_string_property(object *op, int propcode, const char *value)
Definition: plugin_common.cpp:456
region::name
char * name
Shortend name of the region as maps refer to it.
Definition: map.h:275
do_kills
static void do_kills(char *buffer, int size, time_t start, time_t end, const char *reg, kill_format *format)
Definition: cfnewspaper.cpp:219
format_time
static void format_time(timeofday_t *tod, char *buffer, int size)
Definition: cfnewspaper.cpp:91
buf
StringBuffer * buf
Definition: readable.cpp:1565
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
gethook
f_plug_api gethook
Definition: cfnewspaper.cpp:41
kill_format::no_player_death
const char * no_player_death
Definition: cfnewspaper.cpp:196
CFAPI_MAP_PROP_REGION
#define CFAPI_MAP_PROP_REGION
Definition: plugin.h:262
timeofday_t::day
int day
Definition: tod.h:41
logger_database
static sqlite3 * logger_database
Definition: cfnewspaper.cpp:49
is_valid_types_gen.line
line
Definition: is_valid_types_gen.py:34
SvnRevPlugin
CF_PLUGIN char SvnRevPlugin[]
Definition: cfnewspaper.cpp:39
CF_PLUGIN
#define CF_PLUGIN
Definition: plugin_common.h:38
do_region_kills
static void do_region_kills(region *reg, char *buffer, int size, time_t start, time_t end)
Definition: cfnewspaper.cpp:268
f_plug_api
void(* f_plug_api)(int *type,...)
General API function.
Definition: plugin.h:79
cf_init_plugin
int cf_init_plugin(f_plug_api getHooks)
Definition: plugin_common.cpp:146
getPluginProperty
void * getPluginProperty(int *type,...)
Gets a plugin property.
Definition: cfnewspaper.cpp:104
PLUGIN_NAME
#define PLUGIN_NAME
Definition: cfanim.h:32
initPlugin
int initPlugin(const char *iversion, f_plug_api gethooksptr)
Plugin initialisation function.
Definition: cfnewspaper.cpp:98
cfnewspaper.h
do_region
static void do_region(region *reg, char *buffer, int size, time_t start, time_t end)
Definition: cfnewspaper.cpp:286
postInitPlugin
int postInitPlugin(void)
Plugin was initialized, now to finish.
Definition: cfnewspaper.cpp:152
kill_format::many_player_death
const char * many_player_death
Definition: cfnewspaper.cpp:198
newspaper_database
static sqlite3 * newspaper_database
Definition: cfnewspaper.cpp:51
timeofday_t::month
int month
Definition: tod.h:40
kill_format
Definition: cfnewspaper.cpp:195
CFAPI_OBJECT_PROP_NAME_PLURAL
#define CFAPI_OBJECT_PROP_NAME_PLURAL
Definition: plugin.h:131
paper_properties::info_region
int info_region
Definition: cfnewspaper.cpp:185
path
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
get_newspaper_content
static void get_newspaper_content(object *paper, paper_properties *properties, region *reg)
Definition: cfnewspaper.cpp:310
PLUGIN_VERSION
#define PLUGIN_VERSION
Definition: cfanim.h:33
region
This is a game region.
Definition: map.h:274
llevInfo
@ llevInfo
Information.
Definition: logger.h:12
registerGlobalEvent
f_plug_api registerGlobalEvent
Definition: cfnewspaper.cpp:43
closePlugin
int closePlugin(void)
Close the plugin.
Definition: cfnewspaper.cpp:400
object::slaying
sstring slaying
Which race to do double damage to.
Definition: object.h:327
CFAPI_OBJECT_PROP_NAME
#define CFAPI_OBJECT_PROP_NAME
Definition: plugin.h:130
timeofday_t::minute
int minute
Definition: tod.h:44
kill_format::one_monster_death
const char * one_monster_death
Definition: cfnewspaper.cpp:200
do_world_kills
static void do_world_kills(char *buffer, int size, time_t start, time_t end)
Definition: cfnewspaper.cpp:292
default_properties
static paper_properties default_properties
Definition: cfnewspaper.cpp:189
contents
the server will also quite happily load unpacked files as long as they have the right file which is convenient if you want to edit your maps and archetypes live It also contains a few like which have hard coded names and are not identified by extension localdir Usually var crossfire Modern systems probably want var lib crossfire instead Contains data that the server does need to live apartment contents
Definition: server-directories.txt:62
timeofday_t::hour
int hour
Definition: tod.h:43
buffer
if you malloc the data for the buffer
Definition: protocol.txt:2100
kill_format::one_player_death
const char * one_player_death
Definition: cfnewspaper.cpp:197
news_cat
static void news_cat(char *buffer, int size, const char *format,...)
Definition: cfnewspaper.cpp:208
get_region_id
static int get_region_id(region *reg)
Definition: cfnewspaper.cpp:67
cf_object_insert_object
object * cf_object_insert_object(object *op, object *container)
Definition: plugin_common.cpp:1056
CFAPI_OBJECT_PROP_MESSAGE
#define CFAPI_OBJECT_PROP_MESSAGE
Definition: plugin.h:136
svnversion.h
paper_properties::info_world
int info_world
Definition: cfnewspaper.cpp:186
kill_format::many_monster_death
const char * many_monster_death
Definition: cfnewspaper.cpp:201
kill_format
struct kill_format kill_format
cfnewspaper_proto.h
cf_get_time
void cf_get_time(timeofday_t *tod)
Definition: plugin_common.cpp:1549
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
paper_properties::name
const char * name
Definition: cfnewspaper.cpp:184
EVENT_APPLY
#define EVENT_APPLY
Object applied-unapplied.
Definition: events.h:20
reCmp
f_plug_api reCmp
Definition: cfnewspaper.cpp:47