323 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			323 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
| /*****************************************************************************/
 | |
| /* Template for version 2.0 plugins.                                         */
 | |
| /* Contact: yann.chachkoff@myrealbox.com                                     */
 | |
| /*****************************************************************************/
 | |
| /* That code is placed under the GNU General Public Licence (GPL)            */
 | |
| /* (C)2001-2005 by Chachkoff Yann (Feel free to deliver your complaints)     */
 | |
| /*****************************************************************************/
 | |
| /*  CrossFire, A Multiplayer game for X-windows                              */
 | |
| /*                                                                           */
 | |
| /*  Copyright (C) 2008 the Crossfire development team                        */
 | |
| /*                                                                           */
 | |
| /*  This program is free software; you can redistribute it and/or modify     */
 | |
| /*  it under the terms of the GNU General Public License as published by     */
 | |
| /*  the Free Software Foundation; either version 2 of the License, or        */
 | |
| /*  (at your option) any later version.                                      */
 | |
| /*                                                                           */
 | |
| /*  This program is distributed in the hope that it will be useful,          */
 | |
| /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
 | |
| /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
 | |
| /*  GNU General Public License for more details.                             */
 | |
| /*                                                                           */
 | |
| /*  You should have received a copy of the GNU General Public License        */
 | |
| /*  along with this program; if not, write to the Free Software              */
 | |
| /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
 | |
| /*                                                                           */
 | |
| /*****************************************************************************/
 | |
| 
 | |
| /**
 | |
|  * @defgroup plugin_rhg Random house generation plugin
 | |
|  * This plugin links unused exits to random maps.
 | |
|  * The random map parameters vary based on the map it is in, but each exit will always use
 | |
|  * the same random seed to have the same layout and content.
 | |
|  *
 | |
|  * Exits will only point to a random map if both their @ref obj::slaying "slaying" and
 | |
|  * @ref obj::msg "msg" fields are empty.
 | |
|  *
 | |
|  * @todo
 | |
|  * - make more parameters vary based on maps
 | |
|  * - add exits to all towns
 | |
|  *
 | |
|  * @{
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * @file
 | |
|  * This file is part of the @ref plugin_rhg "random house generation plugin".
 | |
|  * See this page for more information.
 | |
|  */
 | |
| 
 | |
| #include <stdarg.h>
 | |
| #include <assert.h>
 | |
| 
 | |
| #include <cfrhg.h>
 | |
| #ifndef __CEXTRACT__
 | |
| #include <cfrhg_proto.h>
 | |
| #endif
 | |
| 
 | |
| /** Link between a map and the exits to generate for it. */
 | |
| typedef struct house_zone_struct {
 | |
|     const char *mappath;        /**< Full map path. */
 | |
|     const char *monsterstyle;   /**< Style of monsters. */
 | |
| } house_zone_struct;
 | |
| 
 | |
| /** Maps we work on. */
 | |
| static const house_zone_struct zones[] = {
 | |
|     /* Scorn */
 | |
|     { "/world/world_104_115", "city" },
 | |
|     { "/world/world_105_115", "city" },
 | |
|     { "/world/world_104_116", "city" },
 | |
|     { "/world/world_105_116", "city" },
 | |
|     /* Navar */
 | |
|     { "/world/world_122_116", "city" },
 | |
|     { "/world/world_121_116", "city" },
 | |
|     { "/world/world_122_117", "city" },
 | |
|     { "/world/world_121_117", "city" },
 | |
|     { NULL, NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Get the random map parameters of a map.
 | |
|  * @param map
 | |
|  * map to get the zone of.
 | |
|  * @return
 | |
|  * NULL if the map shouldn't be processed, else its parameters.
 | |
|  */
 | |
| static const house_zone_struct *get_map_zone(const mapstruct *map) {
 | |
|     int zone;
 | |
| 
 | |
|     for (zone = 0; zones[zone].mappath != NULL; zone++) {
 | |
|         if (strcmp(zones[zone].mappath, map->path) == 0)
 | |
|             return &zones[zone];
 | |
|     }
 | |
| 
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Should we add a random map to this exit?
 | |
|  * @param exit
 | |
|  * exit to check.
 | |
|  * @return
 | |
|  * 1 if a map should be set, 0 else.
 | |
|  */
 | |
| static int is_suitable_exit(object *exit) {
 | |
|     assert(exit);
 | |
| 
 | |
|     if (cf_object_get_int_property(exit, CFAPI_OBJECT_PROP_TYPE) != EXIT)
 | |
|         return 0;
 | |
|     if (cf_object_get_sstring_property(exit, CFAPI_OBJECT_PROP_SLAYING) || cf_object_get_sstring_property(exit, CFAPI_OBJECT_PROP_MESSAGE))
 | |
|         return 0;
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get the random map seed. Will always yield the same value for the same (position included) exit.
 | |
|  * @param exit
 | |
|  * exit to get the seed of.
 | |
|  * @param map
 | |
|  * map the exit is on.
 | |
|  * @return
 | |
|  * random seed.
 | |
|  */
 | |
| static int get_exit_seed(const object *exit, const mapstruct *map) {
 | |
|     char r[500];
 | |
|     int seed = 0, len, w = 0;
 | |
| 
 | |
|     snprintf(r, sizeof(r), "%s!%d,%d*%s", exit->arch->name, exit->x, exit->y, map->path);
 | |
| 
 | |
|     len = strlen(r)-1;
 | |
|     while (len >= 0) {
 | |
|         seed ^= ((int)r[len])<<w;
 | |
|         w += 8;
 | |
|         w = w%32;
 | |
|         len--;
 | |
|     }
 | |
| 
 | |
|     return seed;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Change an empty exit to point to a random map.
 | |
|  * @param exit
 | |
|  * exit to alter.
 | |
|  * @param zone
 | |
|  * zone we're part of, to know the random map parameters.
 | |
|  * @param map
 | |
|  * map the exit is on.
 | |
|  */
 | |
| static void add_exit_to_item(object *exit, const house_zone_struct *zone, const mapstruct *map) {
 | |
|     char params[MAX_BUF];
 | |
| 
 | |
|     assert(exit);
 | |
|     assert(zone);
 | |
| 
 | |
|     snprintf(params, sizeof(params), "layoutstyle onion\n"
 | |
|         "floorstyle indoor\n"
 | |
|         "wallstyle wooden\n"
 | |
|         "monsterstyle %s\n"
 | |
|         "dungeon_level 1\n"
 | |
|         "dungeon_depth 1\n"
 | |
|         "decorstyle furniture\n"
 | |
|         "random_seed %d\n",
 | |
|         zone->monsterstyle,
 | |
|         get_exit_seed(exit, map));
 | |
| 
 | |
|     cf_object_set_string_property(exit, CFAPI_OBJECT_PROP_SLAYING, "/!");
 | |
|     cf_object_set_string_property(exit, CFAPI_OBJECT_PROP_MESSAGE, params);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Checks if the map should be processed, and if so process it.
 | |
|  * @param map
 | |
|  * map to work on.
 | |
|  */
 | |
| static void add_exits_to_map(const mapstruct *map) {
 | |
|     int x, y;
 | |
|     object *item;
 | |
|     const house_zone_struct *zone = get_map_zone(map);
 | |
| 
 | |
|     if (!zone)
 | |
|         return;
 | |
| 
 | |
|     for (x = 0; x < MAP_WIDTH(map); x++) {
 | |
|         for (y = 0; y < MAP_HEIGHT(map); y++) {
 | |
|             item = GET_MAP_OB(map, x, y);
 | |
|             while (item) {
 | |
|                 if (is_suitable_exit(item))
 | |
|                     add_exit_to_item(item, zone, map);
 | |
| 
 | |
|                 item = item->above;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Global server event handling. Only uses EVENT_MAPLOAD.
 | |
|  * @param type
 | |
|  * unused.
 | |
|  * @return
 | |
|  * pointer to integer with value 0.
 | |
|  */
 | |
| CF_PLUGIN void *cfrhg_globalEventListener(int *type, ...) {
 | |
|     va_list args;
 | |
|     static int rv = 0;
 | |
|     mapstruct *map;
 | |
|     int code;
 | |
| 
 | |
|     va_start(args, type);
 | |
|     code = va_arg(args, int);
 | |
| 
 | |
|     rv = 0;
 | |
| 
 | |
|     switch (code) {
 | |
|     case EVENT_MAPLOAD:
 | |
|         map = va_arg(args, mapstruct *);
 | |
|         add_exits_to_map(map);
 | |
|         break;
 | |
|     }
 | |
|     va_end(args);
 | |
| 
 | |
|     return &rv;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Unused.
 | |
|  * @param type
 | |
|  * unused.
 | |
|  * @return
 | |
|  * NULL.
 | |
|  */
 | |
| CF_PLUGIN void *eventListener(int *type, ...) {
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Plugin initialization.
 | |
|  * @param iversion
 | |
|  * server version.
 | |
|  * @param gethooksptr
 | |
|  * function to get hooks.
 | |
|  * @return
 | |
|  * 0.
 | |
|  */
 | |
| CF_PLUGIN int initPlugin(const char *iversion, f_plug_api gethooksptr) {
 | |
|     cf_init_plugin(gethooksptr);
 | |
| 
 | |
|     cf_log(llevDebug, PLUGIN_VERSION " init\n");
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get the plugin identification or full name.
 | |
|  * @param type
 | |
|  * unused.
 | |
|  * @return
 | |
|  * NULL.
 | |
|  */
 | |
| CF_PLUGIN void *getPluginProperty(int *type, ...) {
 | |
|     va_list args;
 | |
|     const char *propname;
 | |
|     int size;
 | |
|     char *buf;
 | |
| 
 | |
|     va_start(args, type);
 | |
|     propname = va_arg(args, const char *);
 | |
| 
 | |
|     if (!strcmp(propname, "Identification")) {
 | |
|         buf = va_arg(args, char *);
 | |
|         size = va_arg(args, int);
 | |
|         va_end(args);
 | |
|         snprintf(buf, size, PLUGIN_NAME);
 | |
|         return NULL;
 | |
|     } else if (!strcmp(propname, "FullName")) {
 | |
|         buf = va_arg(args, char *);
 | |
|         size = va_arg(args, int);
 | |
|         va_end(args);
 | |
|         snprintf(buf, size, PLUGIN_VERSION);
 | |
|         return NULL;
 | |
|     }
 | |
|     va_end(args);
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Unused.
 | |
|  * @param op
 | |
|  * unused.
 | |
|  * @param params
 | |
|  * unused.
 | |
|  * @return
 | |
|  * -1.
 | |
|  */
 | |
| CF_PLUGIN int cfrhg_runPluginCommand(object *op, char *params) {
 | |
|     return -1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Plugin initialisation.
 | |
|  * @return
 | |
|  * 0.
 | |
|  */
 | |
| CF_PLUGIN int postInitPlugin(void) {
 | |
|     cf_log(llevDebug, PLUGIN_VERSION " post init\n");
 | |
| 
 | |
|     cf_system_register_global_event(EVENT_MAPLOAD, PLUGIN_NAME, cfrhg_globalEventListener);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Unloading of plugin.
 | |
|  * @return
 | |
|  * 0.
 | |
|  */
 | |
| CF_PLUGIN int closePlugin(void) {
 | |
|     cf_log(llevDebug, PLUGIN_VERSION " closing\n");
 | |
|     return 0;
 | |
| }
 | |
| /*@}*/
 |