server-1.12/plugins/cfrhg/cfrhg.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;
}
/*@}*/