Crossfire Server, Trunk
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,...)
Definition: plugin_common.cpp:1522
read_parameters
static void read_parameters(void)
Definition: cfnewspaper.cpp:95
line
Install Bug reporting Credits so make sure you have version or later There are files involved in the automatic convert convertall and filelist py GuildList has the list of guilds for the server GuildLocations is what is used by the install script for setting up the maps It has columns in the first is the name of the no spaces The second is the region of the the third is the destination folder for the the fourth is the exit the fifth and sixth are the x and y coords within the exit the seventh eighth and ninth are the exit location for the storage hall If field seven is then it uses the same exit map as for the guild hall itself filelist py has a list of which files to process for each guild hall convert py takes all the files in filelist py and customises them to the specific guild then outputs them into a in the same order that they are listed in GuildLocations convertall py reads the lines from GuildLocations and runs line by line
Definition: README.txt:12
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)
Definition: plugin_common.cpp:1130
llevError
@ llevError
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
send.date
date
Definition: send.py:29
eventListener
int eventListener(int *type,...)
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)
Definition: plugin_common.cpp:1093
SVN_REV
#define SVN_REV
Definition: svnversion.h:2
cfnewspaper_runPluginCommand
int cfnewspaper_runPluginCommand(object *op, char *params)
Definition: cfnewspaper.cpp:133
timeofday_t
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
Definition: map.h:274
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:1552
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:261
diamondslots.results
results
Definition: diamondslots.py:39
autojail.who
who
Definition: autojail.py:3
timeofday_t::day
int day
Definition: tod.h:41
logger_database
static sqlite3 * logger_database
Definition: cfnewspaper.cpp:49
diamondslots.activator
activator
Definition: diamondslots.py:10
make_face_from_files.args
args
Definition: make_face_from_files.py:37
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,...)
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,...)
Definition: cfnewspaper.cpp:104
PLUGIN_NAME
#define PLUGIN_NAME
Definition: cfanim.h:32
initPlugin
int initPlugin(const char *iversion, f_plug_api gethooksptr)
Definition: cfnewspaper.cpp:98
navar-midane_pickup.msg
list msg
Definition: navar-midane_pickup.py:13
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)
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
Definition: map.h:273
llevInfo
@ llevInfo
Definition: logger.h:12
registerGlobalEvent
f_plug_api registerGlobalEvent
Definition: cfnewspaper.cpp:43
closePlugin
int closePlugin(void)
Definition: cfnewspaper.cpp:400
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
give.op
op
Definition: give.py:33
do_world_kills
static void do_world_kills(char *buffer, int size, time_t start, time_t end)
Definition: cfnewspaper.cpp:292
format
Python Guilds Quick outline Add a guild(mapmakers) this is still a problem *after dropping the token to gain access to the stove a woodfloor now appears which is Toolshed Token(found in Guild_HQ) *Note also have multiple gates in place to protect players and items from the mana explosion drop x for Jewelers room *Jewelers room works just need to determine what x is drop x for Thaumaturgy room *Thaumaturgy room works just need to determine what x is drop gold dropping the Firestar named fearless allows access to but I suspect that the drop location of the chest is not as intended because the player is in the way once you enter the chest the exit back to the basement is things such as the message et al reside on teleporters which then transport items to the map as they are when the map is already purchased items reappear in that area From my this does not cause any problems at the moment But this should be corrected fixed Major it s now possible to buy guilds Ryo Update Uploaded guild package to CVS Changes the cauldrons and the charging room I spent a while agonizing over They were natural guild enhancements but much too much value for any reasonable expense to buy them Then I thought that they should be pay access but at a greatly reduced rate SO when you buy a forge or whatever for your guild it is available on a perplayer daily rate but it will be accessable for testing and to DMs to play with Like I said lots still to do with the especially comingt up with quest items for buying things like the new workshops and stuff One of the things I would like some input on would be proposals for additional fields for either the guildhouses or guild datafiles to play with Currently the Guildhouse but there is no reason we can t have more than one measure of a guild perhaps have dues relate to Dues and use points for some other suspended or inactive or when a guild is founded inactive active Guilds have the format
Definition: README.txt:140
default_properties
static paper_properties default_properties
Definition: cfnewspaper.cpp:189
timeofday_t::hour
int hour
Definition: tod.h:43
roll-o-matic.params
params
Definition: roll-o-matic.py:193
kill_format::one_player_death
const char * one_player_death
Definition: cfnewspaper.cpp:197
python_pickup.where
where
Definition: python_pickup.py:7
news_cat
static void news_cat(char *buffer, int size, const char *format,...)
Definition: cfnewspaper.cpp:208
properties
const char * properties[PROPERTY_COUNT]
Definition: ArchetypesModel.cpp:21
givecontents.contents
bool contents
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: givecontents.py:19
animate.event
event
DIALOGCHECK MINARGS 1 MAXARGS 2
Definition: animate.py:17
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
Definition: events.h:20
diamondslots.id
id
Definition: diamondslots.py:53
reCmp
f_plug_api reCmp
Definition: cfnewspaper.cpp:47