Crossfire Server, Branch 1.12
R12190
|
00001 /*****************************************************************************/ 00002 /* Template for version 2.0 plugins. */ 00003 /* Contact: yann.chachkoff@myrealbox.com */ 00004 /*****************************************************************************/ 00005 /* That code is placed under the GNU General Public Licence (GPL) */ 00006 /* (C)2001-2005 by Chachkoff Yann (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 00061 #include <citylife.h> 00062 #include <stdarg.h> 00063 #ifndef __CEXTRACT__ 00064 #include <citylife_proto.h> 00065 #endif 00066 00067 CF_PLUGIN int initPlugin(const char *iversion, f_plug_api gethooksptr) { 00068 cf_init_plugin(gethooksptr); 00069 00070 cf_log(llevDebug, PLUGIN_VERSION " init\n"); 00071 00072 return 0; 00073 } 00074 00075 CF_PLUGIN void *getPluginProperty(int *type, ...) { 00076 va_list args; 00077 const char *propname; 00078 int size; 00079 char *buf; 00080 00081 va_start(args, type); 00082 propname = va_arg(args, const char *); 00083 00084 if (!strcmp(propname, "Identification")) { 00085 buf = va_arg(args, char *); 00086 size = va_arg(args, int); 00087 va_end(args); 00088 snprintf(buf, size, PLUGIN_NAME); 00089 return NULL; 00090 } else if (!strcmp(propname, "FullName")) { 00091 buf = va_arg(args, char *); 00092 size = va_arg(args, int); 00093 va_end(args); 00094 snprintf(buf, size, PLUGIN_VERSION); 00095 return NULL; 00096 } 00097 va_end(args); 00098 return NULL; 00099 } 00100 00101 CF_PLUGIN int citylife_runPluginCommand(object *op, char *params) { 00102 return -1; 00103 } 00104 00106 #define FIRST_MOVE_KEY "citylife_first_move" 00107 00111 typedef struct { 00112 int x; 00113 int y; 00114 } spawn_point; 00115 00120 typedef struct { 00121 int sx, sy, ex, ey; 00122 } spawn_zone; 00123 00127 typedef struct { 00128 const spawn_point *points; 00129 int count_points; 00130 const spawn_zone *zones; 00131 int count_zones; 00132 int population; 00133 const char *mapname; 00134 const char *const *available_archetypes; 00135 int archetypes_count; 00136 } mapzone; 00147 static const spawn_zone scorn_nw_zones[] = { 00148 { 40, 26, 50, 50 } 00149 }; 00150 00152 static const spawn_point scorn_nw_points[] = { 00153 { 41, 37 }, 00154 { 48, 35 }, 00155 { 49, 40 }, 00156 { 47, 22 }, 00157 { 49, 37 } 00158 }; 00159 00161 static const spawn_zone scorn_ne_zones[] = { 00162 { 0, 26, 22, 50 } 00163 }; 00164 00166 static const spawn_point scorn_ne_points[] = { 00167 { 15, 42 }, 00168 { 9, 35 }, 00169 { 15, 29 }, 00170 { 1, 25 }, 00171 { 1, 29 } 00172 }; 00173 00175 static const spawn_zone scorn_sw_zones[] = { 00176 { 41, 0, 50, 10 } 00177 }; 00178 00180 static const spawn_point scorn_sw_points[] = { 00181 { 41, 2 }, 00182 { 46, 8 }, 00183 { 42, 8 } 00184 }; 00185 00187 static const spawn_zone scorn_se_zones[] = { 00188 { 0, 0, 13, 10 } 00189 }; 00190 00192 static const spawn_point scorn_se_points[] = { 00193 { 2, 8 }, 00194 { 11, 8 }, 00195 { 8, 1 }, 00196 { 5, 8 } 00197 }; 00198 00200 static const char *const scorn_archs[] = { 00201 "c_man", 00202 "c_woman", 00203 "child", 00204 "farmer", 00205 "fatman", 00206 "fatwoman", 00207 "guard", 00208 "knight", 00209 "man", 00210 "nun", 00211 "sage", 00212 "woman" 00213 }; 00221 static const mapzone available_zones[] = { 00222 { scorn_nw_points, 5, scorn_nw_zones, 1, 2, "/world/world_104_115", scorn_archs, 12 }, 00223 { scorn_ne_points, 1, scorn_ne_zones, 1, 5, "/world/world_105_115", scorn_archs, 12 }, 00224 { scorn_sw_points, 3, scorn_sw_zones, 1, 5, "/world/world_104_116", scorn_archs, 12 }, 00225 { scorn_se_points, 1, scorn_se_zones, 1, 5, "/world/world_105_116", scorn_archs, 12 }, 00226 { NULL, -1, NULL, -1, 1, "", NULL, 0 }, 00227 }; 00228 00237 static const mapzone *get_zone_for_map(mapstruct *map) { 00238 int test; 00239 00240 for (test = 0; available_zones[test].count_points != -1; test++) { 00241 if (strcmp(available_zones[test].mapname, map->path) == 0) 00242 return &available_zones[test]; 00243 } 00244 return NULL; 00245 } 00246 00254 static object *get_npc(const mapzone *zone) { 00255 int arch = RANDOM()%zone->archetypes_count; 00256 object *npc = cf_create_object_by_name(zone->available_archetypes[arch]); 00257 object *evt; 00258 00259 if (!npc) { 00260 cf_log(llevError, PLUGIN_NAME ": get_npc() got NULL object for %s!\n", zone->available_archetypes[arch]); 00261 return NULL; 00262 } 00263 00264 cf_object_set_flag(npc, FLAG_RANDOM_MOVE, 1); 00265 /* Prevent disease spreading in Scorn, mostly rabies. */ 00266 cf_object_set_flag(npc, FLAG_UNDEAD, 1); 00267 /* add a key so NPC will not disappear in the house it came from */ 00268 cf_object_set_key(npc, FIRST_MOVE_KEY, "1", 1); 00269 00270 evt = cf_create_object_by_name("event_time"); 00271 evt->slaying = cf_add_string(PLUGIN_NAME); 00272 evt->title = cf_add_string(PLUGIN_NAME); 00273 cf_object_insert_object(evt, npc); 00274 00275 return npc; 00276 } 00277 00285 static void add_npc_to_zone(const mapzone *zone, mapstruct *map) { 00286 int which; 00287 object *npc = get_npc(zone); 00288 00289 if (!npc) 00290 return; 00291 which = RANDOM()%zone->count_zones; 00292 if (cf_object_teleport(npc, map, zone->zones[which].sx+RANDOM()%(zone->zones[which].ex-zone->zones[which].sx), zone->zones[which].sy+RANDOM()%(zone->zones[which].ey-zone->zones[which].sy))) { 00293 cf_object_free(npc); 00294 } 00295 } 00296 00304 static void add_npc_to_point(const mapzone *zone, mapstruct *map) { 00305 int which; 00306 object *npc = get_npc(zone); 00307 00308 which = RANDOM()%zone->count_points; 00309 if (cf_object_teleport(npc, map, zone->points[which].x, zone->points[which].y)) { 00310 cf_object_free(npc); 00311 } 00312 } 00313 00319 static void add_npcs_to_map(mapstruct *map) { 00320 int add; 00321 const mapzone *zone = get_zone_for_map(map); 00322 00323 if (!zone) 00324 return; 00325 00326 add = 1+RANDOM()%zone->population; 00327 cf_log(llevDebug, PLUGIN_NAME ": adding %d NPC to map %s.\n", add, map->path); 00328 00329 while (add-- >= 0) { 00330 add_npc_to_zone(zone, map); 00331 } 00332 } 00333 00337 static void add_npc_to_random_map(void) { 00338 int count, test; 00339 mapstruct *list[50]; 00340 int zones[50]; 00341 count = 0; 00342 00343 cf_log(llevDebug, PLUGIN_NAME ": adding NPC to random map.\n"); 00344 00345 for (test = 0; available_zones[test].count_points != -1 && count < 50; test++) { 00346 if ((list[count] = cf_map_has_been_loaded(available_zones[test].mapname)) && (list[count]->in_memory == MAP_IN_MEMORY)) { 00347 zones[count] = test; 00348 count++; 00349 } 00350 } 00351 if (!count) 00352 return; 00353 00354 test = RANDOM()%count; 00355 add_npc_to_point(&available_zones[zones[test]], list[test]); 00356 } 00357 00358 CF_PLUGIN void *citylife_globalEventListener(int *type, ...) { 00359 va_list args; 00360 static int rv = 0; 00361 mapstruct *map; 00362 int code; 00363 00364 va_start(args, type); 00365 code = va_arg(args, int); 00366 00367 rv = 0; 00368 00369 switch (code) { 00370 case EVENT_MAPLOAD: 00371 map = va_arg(args, mapstruct *); 00372 add_npcs_to_map(map); 00373 break; 00374 00375 case EVENT_CLOCK: 00376 if (RANDOM()%40 == 0) 00377 add_npc_to_random_map(); 00378 } 00379 va_end(args); 00380 00381 return &rv; 00382 } 00383 00384 CF_PLUGIN int postInitPlugin(void) { 00385 cf_log(llevDebug, PLUGIN_VERSION " post init\n"); 00386 00387 /* Pick the global events you want to monitor from this plugin */ 00388 00389 /* 00390 cf_system_register_global_event(EVENT_BORN, PLUGIN_NAME, citylife_globalEventListener); 00391 cf_system_register_global_event(EVENT_CRASH, PLUGIN_NAME, citylife_globalEventListener); 00392 cf_system_register_global_event(EVENT_PLAYER_DEATH, PLUGIN_NAME, citylife_globalEventListener); 00393 cf_system_register_global_event(EVENT_GKILL, PLUGIN_NAME, citylife_globalEventListener); 00394 cf_system_register_global_event(EVENT_LOGIN, PLUGIN_NAME, citylife_globalEventListener); 00395 cf_system_register_global_event(EVENT_LOGOUT, PLUGIN_NAME, citylife_globalEventListener); 00396 cf_system_register_global_event(EVENT_MAPENTER, PLUGIN_NAME, citylife_globalEventListener); 00397 cf_system_register_global_event(EVENT_MAPLEAVE, PLUGIN_NAME, citylife_globalEventListener); 00398 cf_system_register_global_event(EVENT_MAPRESET, PLUGIN_NAME, citylife_globalEventListener); 00399 cf_system_register_global_event(EVENT_REMOVE, PLUGIN_NAME, citylife_globalEventListener); 00400 cf_system_register_global_event(EVENT_SHOUT, PLUGIN_NAME, citylife_globalEventListener); 00401 cf_system_register_global_event(EVENT_TELL, PLUGIN_NAME, citylife_globalEventListener); 00402 cf_system_register_global_event(EVENT_MUZZLE, PLUGIN_NAME, citylife_globalEventListener); 00403 cf_system_register_global_event(EVENT_KICK, PLUGIN_NAME, citylife_globalEventListener); 00404 */ 00405 cf_system_register_global_event(EVENT_CLOCK, PLUGIN_NAME, citylife_globalEventListener); 00406 cf_system_register_global_event(EVENT_MAPLOAD, PLUGIN_NAME, citylife_globalEventListener); 00407 /* 00408 cf_system_register_global_event(EVENT_MAPRESET, PLUGIN_NAME, citylife_globalEventListener); 00409 */ 00410 00411 return 0; 00412 } 00413 00414 CF_PLUGIN void *eventListener(int *type, ...) { 00415 static int rv = 1; 00416 va_list args; 00417 char *buf; 00418 object *ground, *who, *activator, *third, *event; 00419 int fix; 00420 const char *value; 00421 00422 va_start(args, type); 00423 00424 who = va_arg(args, object *); 00425 activator = va_arg(args, object *); 00426 third = va_arg(args, object *); 00427 buf = va_arg(args, char *); 00428 fix = va_arg(args, int); 00429 event = va_arg(args, object *); 00430 va_end(args); 00431 00432 /* should our npc disappear? */ 00433 if (RANDOM()%100 < 30) { 00434 for (ground = cf_map_get_object_at(who->map, who->x, who->y); ground; ground = cf_object_get_object_property(ground, CFAPI_OBJECT_PROP_OB_ABOVE)) { 00435 if (ground->type == EXIT) { 00436 object *inv; 00437 00438 value = cf_object_get_key(who, FIRST_MOVE_KEY); 00439 if (strcmp(value, "1") == 0) { 00440 cf_object_set_key(who, FIRST_MOVE_KEY, "0", 1); 00441 break; 00442 } 00443 00444 /* must set inventory as no drop, else it'll just drop on the ground */ 00445 for (inv = cf_object_get_object_property(who, CFAPI_OBJECT_PROP_INVENTORY); inv; inv = cf_object_get_object_property(inv, CFAPI_OBJECT_PROP_OB_BELOW)) 00446 cf_object_set_flag(inv, FLAG_NO_DROP, 1); 00447 00448 cf_log(llevDebug, PLUGIN_NAME ": NPC entering building.\n"); 00449 cf_object_remove(who); 00450 cf_object_free(who); 00451 return &rv; 00452 } 00453 } 00454 } 00455 00456 /* we have to move manually, because during the night NPCs don't move. */ 00457 cf_object_move(who, 1+RANDOM()%8, NULL); 00458 00459 return &rv; 00460 } 00461 00462 CF_PLUGIN int closePlugin(void) { 00463 cf_log(llevDebug, PLUGIN_VERSION " closing\n"); 00464 return 0; 00465 }